并發(fā)技術(shù)05】傳統(tǒng)線程同步通信技術(shù)

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

      我們先來看一個(gè)問題:

      有兩個(gè)線程,子線程先執(zhí)行10次,然后主線程執(zhí)行5次,然后再切換到子線程執(zhí)行10,再主線程執(zhí)行5次……如此往返執(zhí)行50次。

      看完這個(gè)問題,很明顯要用到線程間的通信了, 先分析一下思路:首先肯定要有兩個(gè)線程,然后每個(gè)線程中肯定有個(gè)50次的循環(huán),因?yàn)槊總€(gè)線程都要往返執(zhí)行任務(wù)50次,主線程的任務(wù)是執(zhí)行5次,子線程的任務(wù)是執(zhí)行10次。線程間通信技術(shù)主要用到?wait()?方法和?notify()?方法。?wait()?方法會(huì)導(dǎo)致當(dāng)前線程等待,并釋放所持有的鎖,?notify()?方法表示喚醒在此對(duì)象監(jiān)視器上等待的單個(gè)線程。下面來一步步完成這道線程間通信問題。

      首先不考慮主線程和子線程之間的通信,先把各個(gè)線程所要執(zhí)行的任務(wù)寫好:

      public?class?TraditionalThreadCommunication?{????public?static?void?main(String[]?args)?{????????//開啟一個(gè)子線程????????new?Thread(new?Runnable()?{?????????????????????@Override????????????public?void?run()?{????????????????for(int?i?=?1;?i?<=?50;?i?++)?{?????????????????????????????????????synchronized?(TraditionalThreadCommunication.class)?{????????????????????????//子線程任務(wù):執(zhí)行10次???????????????????????????????????????for(int?j?=?1;j?<=?10;?j?++)?{????????????????????????????System.out.println("sub?thread?sequence?of?"?+?j?+?",?loop?of?"?+?i);????????????????????????}???????????????????????}????????????????}????????????}????????}).start();????????//main方法即主線程????????for(int?i?=?1;?i?<=?50;?i?++)?{????????????synchronized?(TraditionalThreadCommunication.class)?{????????????????//主線程任務(wù):執(zhí)行5次????????????????for(int?j?=?1;j?<=?5;?j?++)?{????????????????????System.out.println("main?thread?sequence?of?"?+?j?+?",?loop?of?"?+?i);????????????????}???????????????}???????????????}????}}

      如上,兩個(gè)線程各有50次大循環(huán),執(zhí)行50次任務(wù),子線程的任務(wù)是執(zhí)行10次,主線程的任務(wù)是執(zhí)行5次。為了保證兩個(gè)線程間的同步問題,所以用了 synchronized 同步代碼塊,并使用了相同的鎖:類的字節(jié)碼對(duì)象。這樣可以保證線程安全。但是這種設(shè)計(jì)不太好,就像我在上一節(jié)的死鎖中寫的一樣,我們可以把線程任務(wù)放到一個(gè)類中,這種設(shè)計(jì)的模式更加結(jié)構(gòu)化,而且把不同的線程任務(wù)放到同一個(gè)類中會(huì)很容易解決同步問題,因?yàn)樵谝粋€(gè)類中很容易使用同一把鎖。所以把上面的程序修改一下:

      public?class?TraditionalThreadCommunication?{????public?static?void?main(String[]?args)?{????????Business?bussiness?=?new?Business();?//new一個(gè)線程任務(wù)處理類????????//開啟一個(gè)子線程????????new?Thread(new?Runnable()?{?????????????????????@Override????????????public?void?run()?{????????????????for(int?i?=?1;?i?<=?50;?i?++)?{????????????????????bussiness.sub(i);????????????????}???????????????????????????}????????}).start();????????//main方法即主線程????????for(int?i?=?1;?i?<=?50;?i?++)?{????????????bussiness.main(i);????????}????}}//要用到的共同數(shù)據(jù)(包括同步鎖)或共同的若干個(gè)方法應(yīng)該歸在同一個(gè)類身上,這種設(shè)計(jì)正好體現(xiàn)了高類聚和程序的健壯性。class?Business?{????public?synchronized?void?sub(int?i)?{????????for(int?j?=?1;j?<=?10;?j?++)?{????????????System.out.println("sub?thread?sequence?of?"?+?j?+?",?loop?of?"?+?i);????????}???????}???????public?synchronized?void?main(int?i)?{????????for(int?j?=?1;j?<=?5;?j?++)?{????????????System.out.println("main?thread?sequence?of?"?+?j?+?",?loop?of?"?+?i);????????}}

      經(jīng)過這樣修改后,程序結(jié)構(gòu)更加清晰了,也更加健壯了,只要在兩個(gè)線程任務(wù)方法上加上 synchronized 關(guān)鍵字即可,用的都是 this 這把鎖。但是現(xiàn)在兩個(gè)線程之間還沒有通信,執(zhí)行的結(jié)果是主線程循環(huán)執(zhí)行任務(wù)50次,然后子線程再循環(huán)執(zhí)行任務(wù)50次,原因很簡(jiǎn)單,因?yàn)橛?synchronized 同步。

      下面繼續(xù)完善程序,讓兩個(gè)線程之間完成題目中所描述的那樣通信:

      public?class?TraditionalThreadCommunication?{????public?static?void?main(String[]?args)?{????????Business?bussiness?=?new?Business();?//new一個(gè)線程任務(wù)處理類????????//開啟一個(gè)子線程????????new?Thread(new?Runnable()?{?????????????????????@Override????????????public?void?run()?{????????????????for(int?i?=?1;?i?<=?50;?i?++)?{????????????????????bussiness.sub(i);????????????????}???????????????????????????}????????}).start();????????//main方法即主線程????????for(int?i?=?1;?i?<=?50;?i?++)?{????????????bussiness.main(i);????????}????}}//要用到共同數(shù)據(jù)(包括同步鎖)或共同的若干個(gè)方法應(yīng)該歸在同一個(gè)類身上,這種設(shè)計(jì)正好體現(xiàn)了高雷劇和程序的健壯性。class?Business?{????private?boolean?bShouldSub?=?true;??????public?synchronized?void?sub(int?i)?{????????while(!bShouldSub)?{?//如果不輪到自己執(zhí)行,就睡????????????try?{????????????????this.wait();?//調(diào)用wait()方法的對(duì)象必須和synchronized鎖對(duì)象一致,這里synchronized在方法上,所以用this????????????}?catch?(InterruptedException?e)?{????????????????//?TODO?Auto-generated?catch?block????????????????e.printStackTrace();????????????}????????}????????for(int?j?=?1;j?<=?10;?j?++)?{????????????System.out.println("sub?thread?sequence?of?"?+?j?+?",?loop?of?"?+?i);????????}???????????bShouldSub?=?false;?//改變標(biāo)記????????this.notify();?//喚醒正在等待的主線程????}????public?synchronized?void?main(int?i)?{????????while(bShouldSub)?{?//如果不輪到自己執(zhí)行,就睡????????????try?{????????????????this.wait();????????????}?catch?(InterruptedException?e)?{????????????????//?TODO?Auto-generated?catch?block????????????????e.printStackTrace();????????????}????????}????????for(int?j?=?1;j?<=?5;?j?++)?{????????????System.out.println("main?thread?sequence?of?"?+?j?+?",?loop?of?"?+?i);????????}????????bShouldSub?=?true;?//改變標(biāo)記????????this.notify();?//喚醒正在等待的子線程????}}

      首先,先不說具體的程序?qū)崿F(xiàn),就從結(jié)構(gòu)上來看,已經(jīng)體會(huì)到了這種設(shè)計(jì)的好處了:主函數(shù)里不用修改任何東西,關(guān)于線程間同步和線程間通信的邏輯全都在 Business 類中,主函數(shù)中的不同線程只需要調(diào)用放在該類中對(duì)應(yīng)的任務(wù)即可。體現(xiàn)了高類聚的好處。

      再看一下具體的代碼,首先定義一個(gè) boolean 型變量來標(biāo)識(shí)哪個(gè)線程該執(zhí)行,當(dāng)不是子線程執(zhí)行的時(shí)候,它就睡,那么很自然主線程就執(zhí)行了,執(zhí)行完了,修改了 bShouldSub 并喚醒了子線程,子線程這時(shí)候再判斷一下 while 不滿足了,就不睡了,就執(zhí)行子線程任務(wù),同樣地,剛剛主線程修改了 bShouldSub 后,第二次循環(huán)來執(zhí)行主線程任務(wù)的時(shí)候,判斷 while 滿足就睡了,等待子線程來喚醒。這樣邏輯就很清楚了,主線程和子線程你一下我一下輪流執(zhí)行各自的任務(wù),這種節(jié)奏共循環(huán)50次。

      另外有個(gè)小小的說明:這里其實(shí)用 if 來判斷也是可以的,但是為什么要用 while 呢?因?yàn)橛袝r(shí)候線程會(huì)假醒(就好像人的夢(mèng)游,明明正在睡,結(jié)果站起來了),如果用的是 if 的話,那么它假醒了后,就不會(huì)再返回去判斷 if 了,那它就很自然的往下執(zhí)行任務(wù),好了,另一個(gè)線程正在執(zhí)行呢,啪嘰一下就與另一個(gè)線程之間相互影響了。但是如果是 while 的話就不一樣了,就算線程假醒了,它還會(huì)判斷一下 while 的,但是此時(shí)另一個(gè)線程在執(zhí)行啊,bShouldSub 并沒有被修改,所以還是進(jìn)到 while 里了,又被睡了~所以很安全,不會(huì)影響另一個(gè)線程!官方 JDK 文檔中也是這么干的。

      如果覺得對(duì)您有幫助,請(qǐng)轉(zhuǎn)發(fā)給更多人吧~

      【并發(fā)技術(shù)05】傳統(tǒng)線程同步通信技術(shù)

      任務(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)容,請(qǐng)聯(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)容,請(qǐng)聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。

      上一篇:【華為云-建站之路】40歲油膩大叔,云速建站,初次心得
      下一篇:excel2003下拉菜單的設(shè)置教程
      相關(guān)文章
      亚洲一区二区成人| 亚洲日本va午夜中文字幕一区| 亚洲午夜精品在线| 久久亚洲美女精品国产精品 | 国产亚洲日韩在线三区| 亚洲国产综合久久天堂| 亚洲成av人片在线观看天堂无码| 女bbbbxxxx另类亚洲| 麻豆亚洲AV成人无码久久精品| 亚洲av无码专区青青草原| 国产精品国产亚洲区艳妇糸列短篇| 亚洲GV天堂GV无码男同| 亚洲欧美一区二区三区日产| 亚洲国产AV无码一区二区三区| 亚洲日韩av无码中文| 亚洲国产AV无码一区二区三区 | 337p日本欧洲亚洲大胆艺术| 久久精品国产亚洲av日韩| 亚洲精品自拍视频| 亚洲一级毛片免费在线观看| 亚洲中文字幕无码av| 亚洲AⅤ男人的天堂在线观看 | 亚洲精品视频免费观看| 中文字幕亚洲不卡在线亚瑟| 亚洲Av无码专区国产乱码DVD| 亚洲国产精品不卡在线电影| 亚洲精品第五页中文字幕| 亚洲1区1区3区4区产品乱码芒果| 中文字幕亚洲男人的天堂网络| 亚洲色成人网站WWW永久四虎| 无码不卡亚洲成?人片| 亚洲人成无码网WWW| 国产亚洲精AA在线观看SEE | 豆国产96在线|亚洲| 亚洲午夜AV无码专区在线播放| 国产亚洲福利精品一区| 4480yy私人影院亚洲| 中文字幕亚洲综合久久综合| 国产尤物在线视精品在亚洲| 亚洲精品高清国产一线久久| 久久综合亚洲色一区二区三区|