成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

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

k00baa / 2383人閱讀

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

為什么需要同步多線程?
線程的同步是指讓多個(gè)運(yùn)行的線程在一起良好地協(xié)作,達(dá)到讓多線程按要求合理地占用釋放資源。我們采用Java中的同步代碼塊和同步方法達(dá)到這樣的目的。比如這樣的解決多線程無固定序執(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é)果是隨機(jī)地去任意插入執(zhí)行,這完全取決于JVM對(duì)于線程的調(diào)度,在很多要求定序執(zhí)行的情況下,這種隨機(jī)執(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);
       }
}

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

線程創(chuàng)建運(yùn)行的范式
在以前我們也有自己的線程創(chuàng)建和運(yùn)行的編程范式,一般是定義一個(gè)執(zhí)行類重寫run()方法,但是這種方式將執(zhí)行體和執(zhí)行的任務(wù)放在了一起,從軟件工程的角度來看不利于解耦。一個(gè)線程的執(zhí)行的意思是說線程通過執(zhí)行對(duì)象執(zhí)行了某個(gè)對(duì)象的某個(gè)任務(wù),從這個(gè)角度來說,將任務(wù)的規(guī)定者從執(zhí)行類中分離出來可以使得多線程編程的各個(gè)角色明晰出來,進(jìn)而獲得良好地解耦,以下就是線程創(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)成同步方法,還可以修飾對(duì)象構(gòu)成同步代碼塊,最終的目的都是一樣的:
給要訪問數(shù)據(jù)的線程添加一個(gè)規(guī)定:一次只允許一個(gè)線程訪問數(shù)據(jù)。只有?當(dāng)前正在訪問數(shù)據(jù)”的線程結(jié)束訪問之后,其他線程才允許訪問這個(gè)數(shù)據(jù)。

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

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

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

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

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

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

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

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時(shí),因?yàn)檫@個(gè)方法就不是僅屬于某個(gè)對(duì)象而是屬于整個(gè)類的了,所以一旦一個(gè)線程進(jìn)入了這個(gè)代碼塊就會(huì)將這個(gè)類的所有對(duì)象的所有synchronized方法或synchronized同步代碼塊鎖定,其他的線程就沒有辦法訪問所有這些對(duì)象的synchronized方法和synchronized代碼塊(注意其他線程還是仍然能訪問這些對(duì)象的非synchronized方法和synchronized代碼塊的),因此這種鎖定是class級(jí)別的。

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同步代碼塊是對(duì)一個(gè)對(duì)象作為參數(shù)進(jìn)行鎖定。

① 如在使用synchronized(this)時(shí),一旦一個(gè)線程進(jìn)入了這個(gè)代碼塊就會(huì)將整個(gè)對(duì)象的所有synchronized方法或synchronized同步代碼塊鎖定,其他的線程就沒有辦法訪問這個(gè)對(duì)象的synchronized方法和synchronized代碼塊(注意其他線程還是仍然能訪問這個(gè)對(duì)象的非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方法實(shí)際上等同于用一個(gè)synchronized塊包住方法中的所有語句,然后在synchronized塊的括號(hào)中傳入this關(guān)鍵字。當(dāng)然,如果是靜態(tài)方法,需要鎖定的則是class對(duì)象。

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

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ā)控制手段,某一時(shí)刻只能有一個(gè)線程執(zhí)行該方法。synchroized塊則是一種細(xì)粒度的并發(fā)控制,只會(huì)將塊中的代碼同步,位于方法內(nèi)synchroized塊之外的代碼是可以被多個(gè)線程同時(shí)訪問到。

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/64615.html

相關(guān)文章

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

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

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

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

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

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

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

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

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

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

    miguel.jiang 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<