日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

第三十六期:如果把线程当作一个人来对待,所有问题都瞬间明白了

發(fā)布時(shí)間:2023/12/10 编程问答 50 豆豆
生活随笔 收集整理的這篇文章主要介紹了 第三十六期:如果把线程当作一个人来对待,所有问题都瞬间明白了 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

7月8日

以下文章來(lái)源于編程新說(shuō)?,作者編程新說(shuō)李新杰

多線程的問(wèn)題都曾經(jīng)困擾過(guò)每個(gè)開發(fā)人員,今天將從全新視角來(lái)解說(shuō),希望讀者都能明白。

強(qiáng)烈建議去運(yùn)行下文章中的示例代碼,自己體會(huì)下。

問(wèn)題究竟出在哪里?

一個(gè)線程執(zhí)行,固然是安全的,但是有時(shí)太慢了,怎么辦?

老祖宗告訴我們,“一方有難,八方支援”,那不就是多叫幾個(gè)線程來(lái)幫忙嘛,好辦呀,多new幾個(gè)不就行了,又不要錢。這樣能管用嗎?繼續(xù)往下看。

俗話說(shuō),“在家靠父母,出門靠朋友”。有了朋友的幫助,就會(huì)事半功倍。是這樣的嗎?

不一定,如果朋友“不靠譜”,結(jié)果竟是在“添亂”。于是就演變?yōu)?#xff0c;“不怕神一樣的對(duì)手,就怕豬一樣的隊(duì)友”。可見(jiàn)“人多力量大”縱然是對(duì)的,但也要配合好才能成事。

人和人是朋友,那線程和線程也是“朋友”,如果多線程之間不能配合好的話,最終也會(huì)變?yōu)椤柏i一樣的隊(duì)友”。事實(shí)證明,這也不是一件易事。且容我慢慢道來(lái)。

開發(fā)是一門技術(shù),管理是一門藝術(shù)。也許你正想帶著兄弟們大干一場(chǎng),可偏偏就有人要辭職。或者你付出了這么多,但別人從來(lái)沒(méi)有感動(dòng)過(guò)。為什么會(huì)這樣呢?

因?yàn)槟忝鎸?duì)的是人。每個(gè)人都是獨(dú)立的個(gè)體,有思想,有靈魂,有情感,有三觀。能夠接受外界的“輸入”,經(jīng)過(guò)“處理”后,能夠產(chǎn)生“輸出”。

說(shuō)白了就是會(huì)自主的分析問(wèn)題,并做出決定。這叫什么呢?答案就是,主觀能動(dòng)性。

擁有主觀能動(dòng)性的物體(比如人),你需要和它協(xié)商著或配合著來(lái)共同完成一件事情,而不能“強(qiáng)迫”它去做什么,因?yàn)檫@樣往往不會(huì)有好的結(jié)果。

費(fèi)了這么多口舌,就是希望把問(wèn)題盡量的簡(jiǎn)單化。終于可以回到程序了,那線程的情況是不是類似的呢?答案是肯定的。

一個(gè)線程準(zhǔn)備好后,經(jīng)過(guò)CPU的調(diào)度,就可以自主的運(yùn)行了。此時(shí)它儼然成了一個(gè)獨(dú)立的個(gè)體,且具有主觀能動(dòng)性。

這本是一件好事,但卻也有不好的一面,那就是你對(duì)它的“掌控”能力變?nèi)趿?#xff0c;頗有一種“將在外,君命有所不受”的感覺(jué)。

可能你不同意這種看法,說(shuō)我可以“強(qiáng)迫”它停止運(yùn)行,調(diào)用Thread類的stop()方法來(lái)直接把它“掐死”,不好意思,該方法已廢棄。

因?yàn)榫€程可能在運(yùn)行一些“關(guān)鍵”代碼(比如轉(zhuǎn)賬),此刻不能被終止。Thread類還有一些其它的方法也都廢棄了,大抵原因其實(shí)都差不多。

講了這么多,相信你已經(jīng)明白了,簡(jiǎn)單總結(jié)一下:

事情起因:線程可以獨(dú)立自主的運(yùn)行,可以認(rèn)為它具有主觀能動(dòng)性。

造成結(jié)果:對(duì)它的掌控能力變?nèi)趿?#xff0c;而且又不能直接把它“干掉”。

解決方案:凡事商量著來(lái),互相配合著把事情完成。

作者觀點(diǎn):其實(shí)就是把線程當(dāng)作人來(lái)對(duì)待。

小試牛刀一下

一旦把線程當(dāng)成人,就來(lái)到了人類的世界,這我們太熟悉了,所以很多問(wèn)題都會(huì)變得非常簡(jiǎn)單明了。一起來(lái)看看吧。


場(chǎng)景一,停止

“大胖,大胖,12點(diǎn)了,該去吃飯了,別寫了”

“好的,好的,稍等片刻,把這幾行代碼寫完就走”

要點(diǎn):把停止的信號(hào)傳達(dá)給別人,別人處理完手頭的事情就自己主動(dòng)停止了。
?

static void stopByFlag() {ARunnable ar = new ARunnable();new Thread(ar).start();ar.tellToStop();}static class ARunnable implements Runnable {volatile boolean stop;void tellToStop() {stop = true;}@Overridepublic void run() {println("進(jìn)入不可停止區(qū)域 1。。。");doingLongTime(5);println("退出不可停止區(qū)域 1。。。");println("檢測(cè)標(biāo)志stop = %s", String.valueOf(stop));if (stop) {println("停止執(zhí)行");return;}println("進(jìn)入不可停止區(qū)域 2。。。");doingLongTime(5);println("退出不可停止區(qū)域 2。。。");}}

解說(shuō):線程在預(yù)設(shè)的地點(diǎn)檢測(cè)flag,來(lái)決定是否停止。

場(chǎng)景二,暫停/恢復(fù)

“大胖,大胖,先別發(fā)請(qǐng)求了,對(duì)方服務(wù)器快掛了”

“好的,好的,等這個(gè)執(zhí)行完就不發(fā)了”

過(guò)了一會(huì)

“大胖,大胖,可以重新發(fā)請(qǐng)求了”

“好的,好的”

要點(diǎn):把暫停的信號(hào)傳達(dá)給別人,別人處理完手頭的事情就自己主動(dòng)暫停了。但是恢復(fù)是無(wú)法自主進(jìn)行的,只能由操作系統(tǒng)來(lái)恢復(fù)線程的執(zhí)行。

static void pauseByFlag() {BRunnable br = new BRunnable();new Thread(br).start();br.tellToPause();sleep(8);br.tellToResume();}static class BRunnable implements Runnable {volatile boolean pause;void tellToPause() {pause = true;}void tellToResume() {synchronized (this) {this.notify();}}@Overridepublic void run() {println("進(jìn)入不可暫停區(qū)域 1。。。");doingLongTime(5);println("退出不可暫停區(qū)域 1。。。");println("檢測(cè)標(biāo)志pause = %s", String.valueOf(pause));if (pause) {println("暫停執(zhí)行");try {synchronized (this) {this.wait();}} catch (InterruptedException e) {e.printStackTrace();}println("恢復(fù)執(zhí)行");}println("進(jìn)入不可暫停區(qū)域 2。。。");doingLongTime(5);println("退出不可暫停區(qū)域 2。。。");}}

解說(shuō):還是在預(yù)設(shè)的地點(diǎn)檢測(cè)flag。然后就是wait/notify配合使用。

場(chǎng)景三,插隊(duì)

“大胖,大胖,讓我站到你前面,不想排隊(duì)了”

“好吧”

要點(diǎn):別人插隊(duì)到你前面,必須等他完事后才輪到你。

static void jqByJoin() {CRunnable cr = new CRunnable();Thread t = new Thread(cr);t.start();sleep(1);try {t.join();} catch (InterruptedException e) {e.printStackTrace();}println("終于輪到我了");}static class CRunnable implements Runnable {@Overridepublic void run() {println("進(jìn)入不可暫停區(qū)域 1。。。");doingLongTime(5);println("退出不可暫停區(qū)域 1。。。");}}

解說(shuō):join方法可以讓某個(gè)線程插到自己前面,等它執(zhí)行完,自己才會(huì)繼續(xù)執(zhí)行。

?

場(chǎng)景四,叫醒

“大胖,大胖,醒醒,醒醒,看誰(shuí)來(lái)了”

“誰(shuí)啊,我去”

要點(diǎn):要把別人從睡夢(mèng)中叫醒,一定要采取稍微暴力一點(diǎn)的手段。
?

static void stopByInterrupt() {DRunnable dr = new DRunnable();Thread t = new Thread(dr);t.start();sleep(2);t.interrupt();}static class DRunnable implements Runnable {@Overridepublic void run() {println("進(jìn)入暫停。。。");try {sleep2(5);} catch (InterruptedException e) {println("收到中斷異常。。。");println("做一些相關(guān)處理。。。");}println("繼續(xù)執(zhí)行或選擇退出。。。");}}

解說(shuō):線程在sleep或wait時(shí),是處于無(wú)法交互的狀態(tài)的,此時(shí)只能使用interrupt方法中斷它,線程會(huì)被激活并收到中斷異常。

常見(jiàn)的協(xié)作配合

上面那些場(chǎng)景,其實(shí)都是對(duì)一個(gè)線程的操作,下面來(lái)看多線程間的一些配合。

事件一,考試

假設(shè)今天考試,20個(gè)學(xué)生,1個(gè)監(jiān)考老師。規(guī)定學(xué)生可以提前交卷,即把卷子留下,直接走人就行了。

但老師必須等到所有的學(xué)生都走后,才可以收卷子,然后裝訂打包。

如果把學(xué)生和老師都看作線程,就是1個(gè)線程和20個(gè)線程的配合問(wèn)題,即等20個(gè)線程都結(jié)束了,這1個(gè)線程才開始。

比如20個(gè)線程分別在計(jì)算數(shù)據(jù),等它們都結(jié)束后得到20個(gè)中間結(jié)果,最后這1個(gè)線程再進(jìn)行后續(xù)匯總、處理等。
?

static final int COUNT = 20;public static void main(String[] args) throws Exception {new Thread(new Teacher(cdl)).start();sleep(1);for (int i = 0; i < COUNT; i++) {new Thread(new Student(i, cdl)).start();}synchronized (ThreadCo1.class) {ThreadCo1.class.wait();}}static CountDownLatch cdl = new CountDownLatch(COUNT);static class Teacher implements Runnable {CountDownLatch cdl;Teacher(CountDownLatch cdl) {this.cdl = cdl;}@Overridepublic void run() {println("老師發(fā)卷子。。。");try {cdl.await();} catch (InterruptedException e) {e.printStackTrace();}println("老師收卷子。。。");}}static class Student implements Runnable {CountDownLatch cdl;int num;Student(int num, CountDownLatch cdl) {this.num = num;this.cdl = cdl;}@Overridepublic void run() {println("學(xué)生(%d)寫卷子。。。", num);doingLongTime();println("學(xué)生(%d)交卷子。。。", num);cdl.countDown();}}

解說(shuō):每完成一個(gè)線程,計(jì)數(shù)器減1,當(dāng)減到0時(shí),被阻塞的線程自動(dòng)執(zhí)行。

?

事件二,旅游

最近景色宜人,公司組織去登山,大伙都來(lái)到了山腳下,登山過(guò)程自由進(jìn)行。

但為了在特定的地點(diǎn)拍集體照,規(guī)定1個(gè)小時(shí)后在半山腰集合,誰(shuí)最后到的,要給大家表演一個(gè)節(jié)目。

然后繼續(xù)登山,在2個(gè)小時(shí)后,在山頂集合拍照,還是誰(shuí)最后到的表演節(jié)目。

接著開始下山了,在2個(gè)小時(shí)后在山腳下集合,點(diǎn)名回家,最后到的照例表演節(jié)目。
?

static final int COUNT = 5;public static void main(String[] args) throws Exception {for (int i = 0; i < COUNT; i++) {new Thread(new Staff(i, cb)).start();}synchronized (ThreadCo2.class) {ThreadCo2.class.wait();}}static CyclicBarrier cb = new CyclicBarrier(COUNT, new Singer());static class Singer implements Runnable {@Overridepublic void run() {println("為大家唱歌。。。");}}static class Staff implements Runnable {CyclicBarrier cb;int num;Staff(int num, CyclicBarrier cb) {this.num = num;this.cb = cb;}@Overridepublic void run() {println("員工(%d)出發(fā)。。。", num);doingLongTime();println("員工(%d)到達(dá)地點(diǎn)一。。。", num);try {cb.await();} catch (Exception e) {e.printStackTrace();}println("員工(%d)再出發(fā)。。。", num);doingLongTime();println("員工(%d)到達(dá)地點(diǎn)二。。。", num);try {cb.await();} catch (Exception e) {e.printStackTrace();}println("員工(%d)再出發(fā)。。。", num);doingLongTime();println("員工(%d)到達(dá)地點(diǎn)三。。。", num);try {cb.await();} catch (Exception e) {e.printStackTrace();}println("員工(%d)結(jié)束。。。", num);}}

?

解說(shuō):某個(gè)線程到達(dá)預(yù)設(shè)點(diǎn)時(shí)就在此等待,等所有的線程都到達(dá)時(shí),大家再一起向下個(gè)預(yù)設(shè)點(diǎn)出發(fā)。如此循環(huán)反復(fù)下去。

事件三,勞動(dòng)

大胖和小白去了創(chuàng)業(yè)公司,公司為了節(jié)約開支,沒(méi)有請(qǐng)專門的保潔人員。讓員工自己掃地和擦桌。

大胖覺(jué)得擦桌輕松,就讓小白去掃地。可小白覺(jué)得掃地太累,也想擦桌。

為了公平起見(jiàn),于是決定,每人先干一半,然后交換工具,再接著干對(duì)方剩下的那一個(gè)半。
?

public static void main(String[] args) throws Exception {new Thread(new Staff("大胖", new Tool("笤帚", "掃地"), ex)).start();new Thread(new Staff("小白", new Tool("抹布", "擦桌"), ex)).start();synchronized (ThreadCo3.class) {ThreadCo3.class.wait();}}static Exchanger<Tool> ex = new Exchanger<>();static class Staff implements Runnable {String name;Tool tool;Exchanger<Tool> ex;Staff(String name, Tool tool, Exchanger<Tool> ex) {this.name = name;this.tool = tool;this.ex = ex;}@Overridepublic void run() {println("%s拿的工具是[%s],他開始[%s]。。。", name, tool.name, tool.work);doingLongTime();println("%s開始交換工具。。。", name);try {tool = ex.exchange(tool);} catch (Exception e) {e.printStackTrace();}println("%s的工具變?yōu)閇%s],他開始[%s]。。。", name, tool.name, tool.work);}}static class Tool {String name;String work;Tool(String name, String work) {this.name = name;this.work = work;}}

解說(shuō):兩個(gè)線程在預(yù)設(shè)點(diǎn)交換變量,先到達(dá)的等待對(duì)方。

事件四,魔性游戲

這是一個(gè)充滿魔性的小游戲,由一個(gè)團(tuán)隊(duì)一起參加。所有人每隔5秒鐘抽一次簽,每個(gè)人有50%的概率留下來(lái)或被淘汰。

留下來(lái)的人下次抽簽時(shí)同樣有50%的概率被淘汰。被淘汰的人下次抽簽時(shí)同樣有50%的概率復(fù)活。

團(tuán)隊(duì)所有成員都被淘汰完,為挑戰(zhàn)失敗,團(tuán)隊(duì)所有成員都回到游戲中(除剛開始外),為挑戰(zhàn)成功。

比如一開始10人參與游戲,第一輪抽簽后,6人留下,4人淘汰。

第二輪抽簽后,留下的6人中4人被淘汰,淘汰的4人中2人復(fù)活,那么目前是4人在游戲中,6人被淘汰。

一直如此繼續(xù)下去,直到10人全部被淘汰,或全部回到游戲中。

可見(jiàn),人數(shù)越多,全部被淘汰的概率越小,但全部回到游戲中的概率也越小。

反之,人數(shù)越少,全部回到游戲中的概率越大,但全部被淘汰的概率也越大。

是不是很有魔性啊。哈哈。
?

static final int COUNT = 6;public static void main(String[] args) throws Exception {new Thread(new Challenger("張三")).start();new Thread(new Challenger("李四")).start();new Thread(new Challenger("王五")).start();new Thread(new Challenger("趙六")).start();new Thread(new Challenger("大胖")).start();new Thread(new Challenger("小白")).start();synchronized (ThreadCo4.class) {ThreadCo4.class.wait();}}static Phaser ph = new Phaser() {protected boolean onAdvance(int phase, int registeredParties) {println2("第(%d)局,剩余[%d]人", phase, registeredParties);return registeredParties == 0 ||(phase != 0 && registeredParties == COUNT);};};static class Challenger implements Runnable {String name;int state;Challenger(String name) {this.name = name;this.state = 0;}@Overridepublic void run() {println("[%s]開始挑戰(zhàn)。。。", name);ph.register();int phase = 0;int h;while (!ph.isTerminated() && phase < 100) {doingLongTime(5);if (state == 0) {if (Decide.goon()) {h = ph.arriveAndAwaitAdvance();if (h < 0)println("No%d.[%s]繼續(xù),但已勝利。。。", phase, name);elseprintln("No%d.[%s]繼續(xù)at(%d)。。。", phase, name, h);} else {state = -1;h = ph.arriveAndDeregister();println("No%d.[%s]退出at(%d)。。。", phase, name, h);}} else {if (Decide.revive()) {state = 0;h = ph.register();if (h < 0)println("No%d.[%s]復(fù)活,但已失敗。。。", phase, name);elseprintln("No%d.[%s]復(fù)活at(%d)。。。", phase, name, h);} else {println("No%d.[%s]沒(méi)有復(fù)活。。。", phase, name);}}phase++;}if (state == 0) {ph.arriveAndDeregister();}println("[%s]結(jié)束。。。", name);}}static class Decide {static boolean goon() {return random(9) > 4;}static boolean revive() {return random(9) < 5;}}


解說(shuō):某個(gè)線程到達(dá)預(yù)設(shè)點(diǎn)后,可以選擇等待同伴或自己退出,等大家都到達(dá)后,再一起向下一個(gè)預(yù)設(shè)點(diǎn)出發(fā),隨時(shí)都可以有新的線程加入,退出的也可以再次加入。

生產(chǎn)與銷售的問(wèn)題

在現(xiàn)實(shí)中,工廠生產(chǎn)出來(lái)的產(chǎn)品會(huì)先放到倉(cāng)庫(kù)存儲(chǔ),銷售人員簽了單子后,會(huì)從倉(cāng)庫(kù)把產(chǎn)品發(fā)給客戶。

如果生產(chǎn)的過(guò)快,倉(cāng)庫(kù)里產(chǎn)品越堆越多,直到把倉(cāng)庫(kù)堆滿,那就必須停止生產(chǎn),因?yàn)闆](méi)地方放了。

此時(shí)只能讓銷售人員趕緊出去簽單子,把產(chǎn)品發(fā)出去,倉(cāng)庫(kù)就有了空間,可以恢復(fù)生產(chǎn)了。

如果銷售的過(guò)快,倉(cāng)庫(kù)里產(chǎn)品越來(lái)越少,直到把倉(cāng)庫(kù)清空,那就必須停止銷售,因?yàn)闆](méi)產(chǎn)品了。

此時(shí)只能讓生產(chǎn)人員趕緊生產(chǎn)產(chǎn)品,把產(chǎn)品放到倉(cāng)庫(kù)里,倉(cāng)庫(kù)里就有了產(chǎn)品,可以恢復(fù)銷售了。

可能會(huì)有人問(wèn),為什么不讓生產(chǎn)和銷售直接掛鉤呢,把倉(cāng)庫(kù)這個(gè)環(huán)節(jié)去掉?

這樣會(huì)造成兩種不好的情況:

一是突然來(lái)了很多單子,生產(chǎn)人員累成死Dog也生產(chǎn)不出來(lái)。

二是很長(zhǎng)時(shí)間沒(méi)有單子,生產(chǎn)人員閑成廢Dog也無(wú)事可做。

用稍微“專業(yè)”點(diǎn)的術(shù)語(yǔ)就是此時(shí)的生產(chǎn)和銷售是一種強(qiáng)耦合的關(guān)系,銷售的波動(dòng)對(duì)生產(chǎn)影響太大。

倉(cāng)庫(kù)就是一個(gè)緩沖區(qū),能有效的吸收波動(dòng),很大程度上減少波動(dòng)的傳遞,起到一種解耦作用,由強(qiáng)耦合變成一種松散耦合。

這其實(shí)就對(duì)應(yīng)計(jì)算機(jī)里經(jīng)典的生產(chǎn)者和消費(fèi)者問(wèn)題。

經(jīng)典的生產(chǎn)者和消費(fèi)者

一到多個(gè)線程充當(dāng)生產(chǎn)者,生產(chǎn)元素。一到多個(gè)線程充當(dāng)消費(fèi)者,消費(fèi)元素。

在兩者之間插入一個(gè)隊(duì)列(Queue)充當(dāng)緩沖區(qū),建立起生產(chǎn)者和消費(fèi)者的松散耦合。

正常情況下,即生產(chǎn)元素的速度和消費(fèi)元素的速度差不多時(shí),生產(chǎn)者和消費(fèi)者其實(shí)是不需要去關(guān)注對(duì)方的。

生產(chǎn)者可以一直生產(chǎn),因?yàn)殛?duì)列里總是有空間。消費(fèi)者可以一直消費(fèi),因?yàn)殛?duì)列里總是有元素。即達(dá)到一個(gè)動(dòng)態(tài)的平衡。

但在特殊情況下,比如生產(chǎn)元素的速度很快,隊(duì)列里沒(méi)有了空間,此時(shí)生產(chǎn)者必須自我“ba工”,開始“睡大覺(jué)”。

一旦消費(fèi)者消費(fèi)了元素之后,隊(duì)列里才會(huì)有空間,生產(chǎn)者才可以重啟生產(chǎn),所以,消費(fèi)者在消費(fèi)完元素后有義務(wù)去叫醒生產(chǎn)者復(fù)工。

更準(zhǔn)確的說(shuō)法應(yīng)該是,只有在生產(chǎn)者“睡大覺(jué)”時(shí),消費(fèi)者消費(fèi)完元素后才需要去叫醒生產(chǎn)者。否則,其實(shí)可以不用叫醒,因?yàn)槿思冶緛?lái)就沒(méi)睡。

反之,如果消費(fèi)元素的速度很快,隊(duì)列里沒(méi)有了元素,只需把上述情況顛倒過(guò)來(lái)即可。

但這樣的話就會(huì)引入一個(gè)新的問(wèn)題,就是要能夠準(zhǔn)備的判斷出對(duì)方有沒(méi)有在睡大覺(jué),為此就必須定義一個(gè)狀態(tài)變量,在自己即將開始睡大覺(jué)時(shí),自己設(shè)置下這個(gè)變量。

對(duì)方通過(guò)檢測(cè)這個(gè)變量,來(lái)決定是否進(jìn)行叫醒操作。當(dāng)自己被叫醒后,首先要做的就是清除一下這個(gè)變量,表明我已經(jīng)醒來(lái)復(fù)工了。

這樣就需要多維護(hù)一個(gè)變量和多了一部分判斷邏輯。可能有些人會(huì)覺(jué)得可以通過(guò)判斷隊(duì)列的“空”或“滿”(即隊(duì)列中的元素?cái)?shù)目)來(lái)決定是否進(jìn)行叫醒操作。

在高并發(fā)下,可能剛剛判斷隊(duì)列不為空,瞬間之后隊(duì)列可能已經(jīng)變?yōu)榭盏牧?#xff0c;這樣會(huì)導(dǎo)致邏輯出錯(cuò)。線程可能永遠(yuǎn)無(wú)法被叫醒。

因此,綜合所有,生產(chǎn)者每生產(chǎn)一個(gè)元素后,都會(huì)通知消費(fèi)者,“現(xiàn)在有元素的,你可以消費(fèi)”。

同樣,消費(fèi)者每消費(fèi)一個(gè)元素后,也會(huì)通知生產(chǎn)者,“現(xiàn)在有空間的,你可以生產(chǎn)”。

很明顯,這些通知很多時(shí)候(即對(duì)方?jīng)]有睡大覺(jué)時(shí))是沒(méi)有真正意義的,不過(guò)無(wú)所謂,只要忽略它們就行了。

就是“寧可錯(cuò)殺一千,也不放過(guò)一個(gè)”。首先要保證是正確的,然后才有資格去BB別的。
?

public static void main(String[] args) {Queue queue = new Queue();new Thread(new Producer(queue)).start();new Thread(new Producer(queue)).start();new Thread(new Consumer(queue)).start();}static class Producer implements Runnable {Queue queue;Producer(Queue queue) {this.queue = queue;}@Overridepublic void run() {try {for (int i = 0; i < 10000; i++) {doingLongTime();queue.putEle(random(10000));}} catch (Exception e) {e.printStackTrace();}}}static class Consumer implements Runnable {Queue queue;Consumer(Queue queue) {this.queue = queue;}@Overridepublic void run() {try {for (int i = 0; i < 10000; i++) {doingLongTime();queue.takeEle();}} catch (Exception e) {e.printStackTrace();}}}static class Queue {Lock lock = new ReentrantLock();Condition prodCond = lock.newCondition();Condition consCond = lock.newCondition();final int CAPACITY = 10;Object[] container = new Object[CAPACITY];int count = 0;int putIndex = 0;int takeIndex = 0;public void putEle(Object ele) throws InterruptedException {try {lock.lock();while (count == CAPACITY) {println("隊(duì)列已滿:%d,生產(chǎn)者開始睡大覺(jué)。。。", count);prodCond.await();}container[putIndex] = ele;println("生產(chǎn)元素:%d", ele);putIndex++;if (putIndex >= CAPACITY) {putIndex = 0;}count++;println("通知消費(fèi)者去消費(fèi)。。。");consCond.signalAll();} finally {lock.unlock();}} public Object takeEle() throws InterruptedException { try {lock.lock();while (count == 0) {println("隊(duì)列已空:%d,消費(fèi)者開始睡大覺(jué)。。。", count);consCond.await();}Object ele = container[takeIndex];println("消費(fèi)元素:%d", ele);takeIndex++;if (takeIndex >= CAPACITY) {takeIndex = 0;}count--;println("通知生產(chǎn)者去生產(chǎn)。。。");prodCond.signalAll();return ele;} finally {lock.unlock();}}}

解說(shuō):其實(shí)就是對(duì)await/signalAll的應(yīng)用,幾乎面試必問(wèn)。

閱讀目錄(置頂)(長(zhǎng)期更新計(jì)算機(jī)領(lǐng)域知識(shí))https://blog.csdn.net/weixin_43392489/article/details/102380691

閱讀目錄(置頂)(長(zhǎng)期更新計(jì)算機(jī)領(lǐng)域知識(shí))https://blog.csdn.net/weixin_43392489/article/details/102380882

閱讀目錄(置頂)(長(zhǎng)期科技領(lǐng)域知識(shí))https://blog.csdn.net/weixin_43392489/article/details/102600114

總結(jié)

以上是生活随笔為你收集整理的第三十六期:如果把线程当作一个人来对待,所有问题都瞬间明白了的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。