java線程通訊的幾種方式

      網(wǎng)友投稿 1021 2025-03-31

      并發(fā)編程中,我們可能會(huì)遇到這樣一個(gè)場景

      A、B兩個(gè)線程并行,但是我希望保證B線程在A線程執(zhí)行完了后再執(zhí)行

      這個(gè)時(shí)候就需要線程間進(jìn)行通訊

      A執(zhí)行完了后對B說一聲,喂,我執(zhí)行完了

      來康康用Java怎么實(shí)現(xiàn)

      1、基于synchronized

      2、基于reentrantLock

      3、基于volatile

      4、基于countDownLatch

      我目前就知道這四種

      1、synchronized+wait() 和 notify()

      wait() 和 notify()都是Object類的通訊方法,注意一點(diǎn),wait和 notify必須搭配synchronized使用,并且notify()不會(huì)釋放鎖

      public class SynchronizedTest { //定義個(gè)year,用來記錄某明星的練習(xí)年數(shù) private static double year; public void run() { //線程A,練習(xí)唱跳rap Thread threadA = new Thread(() -> { synchronized (this) { for (year = 0.5; year <= 5; year += 0.5) { System.out.println("蔡徐雞開始練習(xí)唱跳rap:已練習(xí)" + year + "年"); try { Thread.sleep(288); } catch (InterruptedException e) { e.printStackTrace(); } //眾所周知,練習(xí)兩年半即可出道 if (year == 2.5) { System.out.println("===========================>成功練習(xí)兩年半,出道!!!"); this.notify(); } } } }); //線程B,練習(xí)打籃球 Thread threadB = new Thread(() -> { while (true) { synchronized (this) { try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("蔡徐雞開始練習(xí)打籃球"); } } }); //注意,一定要先啟動(dòng)B,不然會(huì)導(dǎo)致B永遠(yuǎn)拿不到鎖 threadB.start(); threadA.start(); } public static void main(String[] args) { SynchronizedTest test = new SynchronizedTest(); test.run(); } }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      25

      26

      27

      28

      29

      30

      31

      32

      33

      34

      35

      36

      37

      38

      39

      40

      41

      42

      43

      44

      45

      46

      47

      運(yùn)行結(jié)果:

      蔡徐雞開始練習(xí)唱跳rap:已練習(xí)0.5年

      蔡徐雞開始練習(xí)唱跳rap:已練習(xí)1.0年

      蔡徐雞開始練習(xí)唱跳rap:已練習(xí)1.5年

      蔡徐雞開始練習(xí)唱跳rap:已練習(xí)2.0年

      蔡徐雞開始練習(xí)唱跳rap:已練習(xí)2.5年

      ===========================>成功練習(xí)兩年半,出道!!!

      蔡徐雞開始練習(xí)唱跳rap:已練習(xí)3.0年

      蔡徐雞開始練習(xí)唱跳rap:已練習(xí)3.5年

      蔡徐雞開始練習(xí)唱跳rap:已練習(xí)4.0年

      蔡徐雞開始練習(xí)唱跳rap:已練習(xí)4.5年

      蔡徐雞開始練習(xí)唱跳rap:已練習(xí)5.0年

      蔡徐雞開始練習(xí)打籃球

      注意看運(yùn)行結(jié)果,線程A在執(zhí)行notify后并沒有釋放鎖,而是執(zhí)行完當(dāng)前任務(wù)才開始執(zhí)行線程B的任務(wù)

      2、基于ReentrantLock

      ReentrantLock也能實(shí)現(xiàn)線程間通訊,不過有點(diǎn)麻煩,需要結(jié)合ReentrantLock的Condition

      public class LockTest { //定義個(gè)year,用來記錄某明星練習(xí)打籃球的年數(shù) private static double year; public static void main(String[] args) { ReentrantLock lock = new ReentrantLock(); Condition condition = lock.newCondition(); //線程A,練習(xí)唱跳rap Thread threadA = new Thread(() -> { //執(zhí)行業(yè)務(wù)代碼前上鎖 lock.lock(); for (year = 0.5; year <= 5; year += 0.5) { System.out.println("蔡徐雞開始練習(xí)唱跳rap:已練習(xí)" + year + "年"); try { Thread.sleep(288); } catch (InterruptedException e) { e.printStackTrace(); } //眾所周知,練習(xí)兩年半即可出道 if (year == 2.5) { System.out.println("===========================>成功練習(xí)兩年半,出道!!!"); //喚醒等待中的線程 condition.signal(); } } //業(yè)務(wù)代碼執(zhí)行完后解鎖 lock.unlock(); }); //線程B,練習(xí)打籃球 Thread threadB = new Thread(() -> { //執(zhí)行業(yè)務(wù)代碼前上鎖 lock.lock(); try { //讓線程等待,如果計(jì)數(shù)器為0的話,則立即執(zhí)行 condition.await(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("蔡徐老母雞開始練習(xí)打籃球"); //業(yè)務(wù)代碼執(zhí)行完后解鎖 lock.unlock(); }); //注意,一定要先啟動(dòng)B,不然會(huì)導(dǎo)致B永遠(yuǎn)拿不到鎖 threadB.start(); threadA.start(); } }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      java線程間通訊的幾種方式

      23

      24

      25

      26

      27

      28

      29

      30

      31

      32

      33

      34

      35

      36

      37

      38

      39

      40

      41

      42

      43

      44

      45

      46

      47

      運(yùn)行結(jié)果:

      蔡徐雞開始練習(xí)唱跳rap:已練習(xí)0.5年

      蔡徐雞開始練習(xí)唱跳rap:已練習(xí)1.0年

      蔡徐雞開始練習(xí)唱跳rap:已練習(xí)1.5年

      蔡徐雞開始練習(xí)唱跳rap:已練習(xí)2.0年

      蔡徐雞開始練習(xí)唱跳rap:已練習(xí)2.5年

      ===========================>成功練習(xí)兩年半,出道!!!

      蔡徐雞開始練習(xí)唱跳rap:已練習(xí)3.0年

      蔡徐雞開始練習(xí)唱跳rap:已練習(xí)3.5年

      蔡徐雞開始練習(xí)唱跳rap:已練習(xí)4.0年

      蔡徐雞開始練習(xí)唱跳rap:已練習(xí)4.5年

      蔡徐雞開始練習(xí)唱跳rap:已練習(xí)5.0年

      蔡徐老母雞開始練習(xí)打籃球

      效果和synchronized+wait() 和 notify()一樣一樣的

      3、基于volatile

      使用共享變量也能實(shí)現(xiàn),用volatile即可,原理就是多個(gè)線程共同監(jiān)聽同個(gè)變量,根據(jù)變量的值變化來執(zhí)行對應(yīng)的任務(wù),此處volatile的作用就是讓其它線程能即時(shí)感知變量值的改變

      public class volatileTest { //定義一個(gè)共享變量,注意,必須用volatile修飾 static volatile boolean flag = false; //定義個(gè)year,用來記錄某明星練習(xí)打籃球的年數(shù) private static double year; public static void main(String[] args) { //線程A,練習(xí)唱跳rap Thread threadA = new Thread(() -> { while (true) { if (!flag) { for (year = 0.5; year <= 5; year += 0.5) { System.out.println("蔡徐雞開始練習(xí)唱跳rap:已練習(xí)" + year + "年"); try { Thread.sleep(288); } catch (InterruptedException e) { e.printStackTrace(); } //眾所周知,練習(xí)兩年半即可出道 if (year == 2.5) { System.out.println("===========================>成功練習(xí)兩年半,出道!!!"); year = 0.5; flag = true; break; } } } } }); //線程B,練習(xí)打籃球 Thread threadB = new Thread(() -> { while (true) { if (flag) { System.out.println("蔡徐老母雞開始練習(xí)打籃球"); break; } } }); // 啟動(dòng)線程 threadA.start(); threadB.start(); } }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      25

      26

      27

      28

      29

      30

      31

      32

      33

      34

      35

      36

      37

      38

      39

      40

      41

      42

      43

      運(yùn)行結(jié)果:

      蔡徐雞開始練習(xí)唱跳rap:已練習(xí)0.5年

      蔡徐雞開始練習(xí)唱跳rap:已練習(xí)1.0年

      蔡徐雞開始練習(xí)唱跳rap:已練習(xí)1.5年

      蔡徐雞開始練習(xí)唱跳rap:已練習(xí)2.0年

      蔡徐雞開始練習(xí)唱跳rap:已練習(xí)2.5年

      ===========================>成功練習(xí)兩年半,出道!!!

      蔡徐老母雞開始練習(xí)打籃球

      3、基于CountDownLatch

      CountDownLatch是JUC包下的一個(gè)并發(fā)編程工具,主要有兩個(gè)方法,countDown和await,CountDownLatch底層維護(hù)了一個(gè)計(jì)數(shù)器,在實(shí)例化的時(shí)候設(shè)置,當(dāng)調(diào)用countDown方法時(shí),計(jì)數(shù)器減一,如果計(jì)數(shù)器在減一前已經(jīng)為0,那么什么都不會(huì)發(fā)生,如果減一后變成0,則喚醒所有等待的線程;await方法會(huì)使當(dāng)前線程等待,直到計(jì)數(shù)器為0

      public class CountDownLatchTest { //定義個(gè)year,用來記錄某明星練習(xí)打籃球的年數(shù) private static double year; public static void main(String[] args) { CountDownLatch latch = new CountDownLatch(1); //線程A,練習(xí)唱跳rap Thread threadA = new Thread(() -> { for (year = 0.5; year <= 5; year += 0.5) { System.out.println("蔡徐雞開始練習(xí)唱跳rap:已練習(xí)" + year + "年"); try { Thread.sleep(288); } catch (InterruptedException e) { e.printStackTrace(); } //眾所周知,練習(xí)兩年半即可出道 if (year == 2.5) { System.out.println("===========================>成功練習(xí)兩年半,出道!!!"); //計(jì)數(shù)器減一 latch.countDown(); } } }); //線程B,練習(xí)打籃球 Thread threadB = new Thread(() -> { try { //讓線程等待,如果計(jì)數(shù)器為0的話,則立即執(zhí)行 latch.await(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("蔡徐老母雞開始練習(xí)打籃球"); }); // 啟動(dòng)線程 threadA.start(); threadB.start(); } }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      25

      26

      27

      28

      29

      30

      31

      32

      33

      34

      35

      36

      37

      38

      運(yùn)行結(jié)果:

      蔡徐雞開始練習(xí)唱跳rap:已練習(xí)0.5年

      蔡徐雞開始練習(xí)唱跳rap:已練習(xí)1.0年

      蔡徐雞開始練習(xí)唱跳rap:已練習(xí)1.5年

      蔡徐雞開始練習(xí)唱跳rap:已練習(xí)2.0年

      蔡徐雞開始練習(xí)唱跳rap:已練習(xí)2.5年

      ===========================>成功練習(xí)兩年半,出道!!!

      蔡徐雞開始練習(xí)唱跳rap:已練習(xí)3.0年

      蔡徐老母雞開始練習(xí)打籃球

      蔡徐雞開始練習(xí)唱跳rap:已練習(xí)3.5年

      蔡徐雞開始練習(xí)唱跳rap:已練習(xí)4.0年

      蔡徐雞開始練習(xí)唱跳rap:已練習(xí)4.5年

      蔡徐雞開始練習(xí)唱跳rap:已練習(xí)5.0年

      如果你多運(yùn)行幾次,你會(huì)發(fā)現(xiàn)線程B執(zhí)行的時(shí)機(jī)是隨機(jī)的,但永遠(yuǎn)在計(jì)數(shù)器為0后才開始執(zhí)行,也就是說計(jì)數(shù)器為0后,線程A和線程B誰搶到鎖就誰執(zhí)行

      文中所有demo都是復(fù)制即可運(yùn)行,大家還是要多動(dòng)手,家里有條件的都用idea跑一跑,沒條件的可以用手抄

      嚶~

      ok我話說完

      Java JDK 任務(wù)調(diào)度

      版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。

      版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。

      上一篇:wps表格行列數(shù)怎么統(tǒng)計(jì)圖文教程(wps表格如何統(tǒng)計(jì)每行有多少個(gè)√這個(gè)符號)
      下一篇:什么是甘特圖項(xiàng)目進(jìn)度評估?
      相關(guān)文章
      亚洲人色婷婷成人网站在线观看| 久久久久久亚洲av无码蜜芽| 欧美亚洲国产SUV| 精品无码一区二区三区亚洲桃色 | 国产亚洲精品自在久久| 中文亚洲AV片在线观看不卡| 亚洲日韩在线观看免费视频| 亚洲精品tv久久久久| 亚洲?v女人的天堂在线观看| 亚洲AⅤ优女AV综合久久久| 激情婷婷成人亚洲综合| 国产成人高清亚洲一区久久| 老子影院午夜伦不卡亚洲| 国产成人综合亚洲一区| 亚洲国产精品国产自在在线 | 亚洲AⅤ永久无码精品AA| avtt亚洲天堂| 国产精品亚洲玖玖玖在线观看| 亚洲无码黄色网址| 国产偷国产偷亚洲清高动态图| 国产亚洲人成网站在线观看| 亚洲综合网站色欲色欲| 国产AV无码专区亚洲AV男同| 亚洲电影一区二区三区| 久久久久久亚洲AV无码专区 | jizzjizz亚洲| 亚洲伊人色欲综合网| 亚洲AV综合色区无码另类小说 | 亚洲国产精品无码久久九九大片| 亚洲av色香蕉一区二区三区| 国产亚洲视频在线观看| 亚洲精品成人a在线观看| 自拍偷自拍亚洲精品被多人伦好爽| 亚洲欧洲美洲无码精品VA| 亚洲av无码国产精品色午夜字幕 | 亚洲国产成人久久一区久久| 中文字幕不卡亚洲| 久久亚洲伊人中字综合精品| 久久夜色精品国产噜噜亚洲AV| 亚洲成a人片77777群色| 亚洲日韩国产二区无码|