亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

Java多線程:Java多線程同步與synchronized

k00baa / 2436人閱讀

摘要:尤其關(guān)鍵的是,當(dāng)一個線程訪問的一個同步代碼塊或同步方法時,其他線程對中所有其它同步代碼塊或同步方法的訪問將被阻塞。同步代碼塊是對一個對象作為參數(shù)進行鎖定。

為什么需要同步多線程?
線程的同步是指讓多個運行的線程在一起良好地協(xié)作,達到讓多線程按要求合理地占用釋放資源。我們采用Java中的同步代碼塊和同步方法達到這樣的目的。比如這樣的解決多線程無固定序執(zhí)行的問題:

public class TwoThreadTest {
        public static void main(String[] args) {
              Thread th1= new MyThread1();
              Thread th2= new MyThread2();
              th1.start();
              th2.start();
       }
}

class MyThread2 extends Thread{
        @Override
        public void run() {
               for( int i=0;i<10;i++)
                     System. out.println( "thread 1 counter:"+i);
       }
}

class MyThread1 extends Thread{
        @Override
        public void run() {
               for( int i=0;i<10;i++)
                     System. out.println( "thread 2 counter:"+i);
       }      
}

這種狀態(tài)下多線程執(zhí)行的結(jié)果是隨機地去任意插入執(zhí)行,這完全取決于JVM對于線程的調(diào)度,在很多要求定序執(zhí)行的情況下,這種隨機執(zhí)行的狀態(tài)顯然是不合要求的。

public class ThreadTest {
        public static void main(String[] args) {
              MyThread thread = new MyThread();
              Thread th1= new Thread(thread);
              Thread th2= new Thread(thread);
              th1.start();
              th2.start();
       }

}

class MyThread implements Runnable{
        @Override
        public synchronized void run() {
               for( int i=0;i<10;i++)
                     System. out.println(Thread. currentThread().getName()+" counter:"+i);
       }
}

使用了同步方法后我們就可以控制線程獨占執(zhí)行體對象,這樣在執(zhí)行的過程中就可以使得線程將執(zhí)行體上的任務(wù)一次性執(zhí)行完后退出鎖定狀態(tài),JVM再調(diào)度另一個線程進來一次性運行執(zhí)行體內(nèi)的任務(wù)。

線程創(chuàng)建運行的范式
在以前我們也有自己的線程創(chuàng)建和運行的編程范式,一般是定義一個執(zhí)行類重寫run()方法,但是這種方式將執(zhí)行體和執(zhí)行的任務(wù)放在了一起,從軟件工程的角度來看不利于解耦。一個線程的執(zhí)行的意思是說線程通過執(zhí)行對象執(zhí)行了某個對象的某個任務(wù),從這個角度來說,將任務(wù)的規(guī)定者從執(zhí)行類中分離出來可以使得多線程編程的各個角色明晰出來,進而獲得良好地解耦,以下就是線程創(chuàng)建和執(zhí)行的編程范式:

public class FormalThreadClass {
        public static void main(String[] args) {
              Thread thread = new Thread( new MyRunnable());
              thread.start();
       }
}

class MyRunnable implements Runnable{
       MyTask myTask = new MyTask();
        @Override
        public void run() {
               myTask.doTask();
       }
}

class MyTask{
        public void doTask() {
              System. out.println( "This is real Tasking");
       }
}

synchronized關(guān)鍵字
synchronized可以用來修飾方法以構(gòu)成同步方法,還可以修飾對象構(gòu)成同步代碼塊,最終的目的都是一樣的:
給要訪問數(shù)據(jù)的線程添加一個規(guī)定:一次只允許一個線程訪問數(shù)據(jù)。只有?當(dāng)前正在訪問數(shù)據(jù)”的線程結(jié)束訪問之后,其他線程才允許訪問這個數(shù)據(jù)。

關(guān)于synchronized關(guān)鍵字,有以下幾點來說明:

當(dāng)它用來修飾一個方法或者一個代碼塊的時候,能夠保證在同一時刻最多只有一個線程執(zhí)行該段代碼。

當(dāng)兩個并發(fā)線程訪問同一個對象object中的這個synchronized同步代碼塊或同步方法時,一個時間內(nèi)只能有一個線程得到執(zhí)行。另一個線程必須等待當(dāng)前線程執(zhí)行完這個代碼塊或同步方法以后才能執(zhí)行該代碼塊或同步方法。

然而,當(dāng)一個線程訪問object的一個synchronized同步代碼塊或同步方法時,另一個線程仍然可以訪問該object中的非synchronized同步代碼塊或非synchronized同步方法。

尤其關(guān)鍵的是,當(dāng)一個線程訪問object的一個synchronized同步代碼塊或同步方法時,其他線程對object中所有其它synchronized同步代碼塊或同步方法的訪問將被阻塞。

1.以下這個例子可以說明synchronized方法的這些特性,同步代碼塊也是一樣:

① synchronized方法表面上它只是鎖定了當(dāng)前的方法本身,實際上當(dāng)synchronized方法起作用的時候,整個對象的帶有synchronized的方法都將被鎖定,這也就是為什么當(dāng)一個線程執(zhí)行一個synchronized方法時,其他的線程除了不能訪問當(dāng)前的同步方法外還并不能訪問其他的同步方法,而只能訪問非synchronized方法,因為這種鎖定是對象級別的。

public class ThreadTest {
        public static void main(String[] args) {
               final MyTask myTask = new MyTask();
              Thread thread1 = new Thread( new Runnable() {
                      public void run() {
                           myTask.doTask1();
                     }
              });
              Thread thread2 = new Thread( new Runnable() {
                      public void run() {
                           myTask.doTask2();
                     }
              });
              thread1.start();
              thread2.start();
       }
}

class MyTask{
        public synchronized void doTask1() {
               for ( int i = 0; i < 5; i++) {
                     System. out.println( "1 This is real Tasking "+i);
              }
       }
        public void doTask2() {
               for ( int i = 0; i < 5; i++) {
                     System. out.println( "2 This is real Tasking "+i);
              }
       }
}

② 如使在靜態(tài)方法中用synchronized時,因為這個方法就不是僅屬于某個對象而是屬于整個類的了,所以一旦一個線程進入了這個代碼塊就會將這個類的所有對象的所有synchronized方法或synchronized同步代碼塊鎖定,其他的線程就沒有辦法訪問所有這些對象的synchronized方法和synchronized代碼塊(注意其他線程還是仍然能訪問這些對象的非synchronized方法和synchronized代碼塊的),因此這種鎖定是class級別的。

public class FormalThreadClass {
        public static void main(String[] args) {
              MyTask myTask1 = new MyTask();
              MyTask myTask2 = new MyTask();
              Thread thread1 = new Thread( new MyRunnable(myTask1));
              Thread thread2 = new Thread( new MyRunnable(myTask2));
              thread1.start();
              thread2.start();
       }
}

class MyRunnable implements Runnable {
       MyTask myTask;
        public MyRunnable(MyTask myTask) {
               this. myTask = myTask;
       }
        @Override
        public void run() {
              MyTask. doTask();
       }
}

class MyTask {
        public static synchronized void doTask() {
               for ( int i = 0; i < 5; i++) {
                     System. out.println(Thread. currentThread().getName()+" running "+i);
              }
       }
}

2.synchronized同步代碼塊是對一個對象作為參數(shù)進行鎖定。

① 如在使用synchronized(this)時,一旦一個線程進入了這個代碼塊就會將整個對象的所有synchronized方法或synchronized同步代碼塊鎖定,其他的線程就沒有辦法訪問這個對象的synchronized方法和synchronized代碼塊(注意其他線程還是仍然能訪問這個對象的非synchronized方法和synchronized代碼塊的)。

public class ThreadTest {
        public static void main(String[] args) {
               final MyTask myTask = new MyTask();
              Thread thread1 = new Thread( new Runnable() {
                      public void run() {
                           myTask.doTask1();
                     }
              });
              Thread thread2 = new Thread( new Runnable() {
                      public void run() {
                           myTask.doTask2();
                     }
              });
              thread1.start();
              thread2.start();
       }
}

class MyTask {
        public void doTask1() {

               synchronized (this) {
                      for ( int i = 0; i < 5; i++) {
                           System. out.println( "1 is running");
                     }
              }

       }

        public void doTask2() {
               for ( int i = 0; i < 5; i++) {
                     System. out.println( "2 is running");
              }
       }
}

所以:synchronized方法實際上等同于用一個synchronized塊包住方法中的所有語句,然后在synchronized塊的括號中傳入this關(guān)鍵字。當(dāng)然,如果是靜態(tài)方法,需要鎖定的則是class對象。

① 如在使用synchronized(.class)時,一旦一個線程進入了這個代碼塊就會將整個類的所有這個synchronized(.class) 同步代碼塊鎖定,其他的線程就沒有辦法訪問這個對象的synchronized(**.class) 代碼塊,這種鎖也是class級別的,但要注意在這種情況下,其他線程仍然是可以訪問僅做了synchronized的代碼塊或非靜態(tài)方法的,因為它們僅僅是對當(dāng)前對象的鎖定。

public class FormalThreadClass {
        public static void main(String[] args) {
              MyTask myTask1 = new MyTask();
              MyTask myTask2 = new MyTask();
              Thread thread1 = new Thread( new MyRunnable(myTask1));
              Thread thread2 = new Thread( new MyRunnable(myTask2));
              thread1.start();
              thread2.start();
       }
}

class MyRunnable implements Runnable {
       MyTask myTask;
        public MyRunnable(MyTask myTask) {
               this. myTask = myTask;
       }
        @Override
        public void run() {
               myTask.doTask();
       }
}

class MyTask {
        public  void doTask() {
               synchronized (MyTask.class ) {
                      for ( int i = 0; i < 5; i++) {
                           System. out.println(Thread. currentThread().getName()+" running "+i);
                     }
              }
       }
}

總結(jié)起來這一部分:
synchronized方法是一種粗粒度的并發(fā)控制手段,某一時刻只能有一個線程執(zhí)行該方法。synchroized塊則是一種細粒度的并發(fā)控制,只會將塊中的代碼同步,位于方法內(nèi)synchroized塊之外的代碼是可以被多個線程同時訪問到。

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/64615.html

相關(guān)文章

  • Java 線程核心技術(shù)梳理(附源碼)

    摘要:本文對多線程基礎(chǔ)知識進行梳理,主要包括多線程的基本使用,對象及變量的并發(fā)訪問,線程間通信,的使用,定時器,單例模式,以及線程狀態(tài)與線程組。源碼采用構(gòu)建,多線程這部分源碼位于模塊中。通知可能等待該對象的對象鎖的其他線程。 本文對多線程基礎(chǔ)知識進行梳理,主要包括多線程的基本使用,對象及變量的并發(fā)訪問,線程間通信,lock的使用,定時器,單例模式,以及線程狀態(tài)與線程組。 寫在前面 花了一周時...

    Winer 評論0 收藏0
  • Java線程學(xué)習(xí)(二)synchronized關(guān)鍵字(2)

    摘要:關(guān)鍵字加到非靜態(tài)方法上持有的是對象鎖。線程和線程持有的鎖不一樣,所以和運行同步,但是和運行不同步。所以盡量不要使用而使用參考多線程編程核心技術(shù)并發(fā)編程的藝術(shù)如果你覺得博主的文章不錯,歡迎轉(zhuǎn)發(fā)點贊。 系列文章傳送門: Java多線程學(xué)習(xí)(一)Java多線程入門 Java多線程學(xué)習(xí)(二)synchronized關(guān)鍵字(1) java多線程學(xué)習(xí)(二)synchronized關(guān)鍵字(2) J...

    Batkid 評論0 收藏0
  • Java線程學(xué)習(xí)(二)synchronized關(guān)鍵字(1)

    摘要:轉(zhuǎn)載請備注地址多線程學(xué)習(xí)二將分為兩篇文章介紹同步方法另一篇介紹同步語句塊。如果兩個線程同時操作對象中的實例變量,則會出現(xiàn)非線程安全,解決辦法就是在方法前加上關(guān)鍵字即可。 轉(zhuǎn)載請備注地址: https://blog.csdn.net/qq_3433... Java多線程學(xué)習(xí)(二)將分為兩篇文章介紹synchronized同步方法另一篇介紹synchronized同步語句塊。系列文章傳送門...

    xuxueli 評論0 收藏0
  • java線程編程核心技術(shù) 2

    摘要:在兩個線程訪問同一個對象中的同步方法時一定是線程安全的。當(dāng)一個線程訪問的一個同步代碼塊時,其他線程對同一個鐘所有其他同步代碼塊的訪問被阻塞,這說明使用的對象監(jiān)視器是一個。 非線程安全其實會在多個線程對同一個對象中的實例變量進行并發(fā)訪問時發(fā)生,產(chǎn)生的后果就是臟讀,也就是取到的數(shù)據(jù)其實是被更改過的。而線程安全就是以獲得的實例變量的值是經(jīng)過同步處理的,不會出現(xiàn)臟讀的現(xiàn)象。 非線程安全問題存...

    wangxinarhat 評論0 收藏0
  • 值得保存的 synchronized 關(guān)鍵字總結(jié)

    摘要:無論是互斥鎖,還是自旋鎖,在任何時刻,最多只能有一個保持者,也就說,在任何時刻最多只能有一個執(zhí)行單元獲得鎖。另外在中引入了自適應(yīng)的自旋鎖。和關(guān)鍵字的總結(jié)推薦一 該文已加入開源文檔:JavaGuide(一份涵蓋大部分Java程序員所需要掌握的核心知識)。地址:https://github.com/Snailclimb... 本文是對 synchronized 關(guān)鍵字使用、底層原理、JD...

    miguel.jiang 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<