Java线程详解(9)-并发协作
Java線程:并發協作-生產者消費者模型
? ? ? ? 對于多線程程序來說,不管任何編程語言,生產者和消費者模型都是最經典的。就像學習每一門編程語言一樣,Hello World!都是最經典的例子。
????????實際上,準確說應該是“生產者-消費者-倉儲”模型,離開了倉儲,生產者消費者模型就顯得沒有說服力了。
????????對于此模型,應該明確一下幾點:
????????此模型將要結合java.lang.Object的wait與notify、notifyAll方法來實現以上的需求。這是非常重要的。
/**?*?Java線程:并發協作-生產者消費者模型?*/?? public?class?Test?{??public?static?void?main(String[]?args)?{??Godown?godown=new?Godown(30);??Consumer?c1=new?Consumer(50,godown);??Consumer?c2=new?Consumer(20,godown);??Consumer?c3=new?Consumer(30,godown);??Producer?p1=new?Producer(10,godown);??Producer?p2=new?Producer(10,godown);??Producer?p3=new?Producer(10,godown);??Producer?p4=new?Producer(10,godown);??Producer?p5=new?Producer(10,godown);??Producer?p6=new?Producer(10,godown);??Producer?p7=new?Producer(80,godown);??c1.start();??c2.start();??c3.start();??p1.start();??p2.start();??p3.start();??p4.start();??p5.start();??p6.start();??p7.start();??}?? }?? /**?*?倉庫?*/?? class?Godown{??public?static?final?int?max_size=100;//最大庫存量??public?int?curnum;//當前庫存量??Godown()?{??}??Godown(int?curnum){??this.curnum=curnum;??}??/**?*?生產指定數量的產品?*/??public?synchronized?void?produce(int?neednum){??//測試是否需要生產??while(neednum+curnum>max_size){??System.out.println("要生產的產品數量"?+?neednum?+"超過剩余庫存量"?+?(max_size?-?curnum)?+",暫時不能執行生產任務!");??try?{??//當前的生產線程等待??wait();??}?catch?(InterruptedException?e)?{??e.printStackTrace();??}??}??//滿足生產條件,則進行生產,這里簡單的更改當前庫存量??curnum+=neednum;??System.out.println("已經生產了"+neednum+"個產品,現倉儲量為"+curnum);??//喚醒在此對象監視器上等待的所有線程??notifyAll();??}??/**?*?消費指定數量的產品?*/??public?synchronized?void?consume(int?neednum){??//測試是否可以消費??while(curnum<neednum){??try?{??//當前的生產線程等待??wait();??}?catch?(InterruptedException?e)?{??e.printStackTrace();??}??}??//滿足消費條件,則進行消費,這里簡單的更改當前庫存??curnum-=neednum;??System.out.println("已經消費了"?+?neednum?+"個產品,現倉儲量為"?+?curnum);??//喚醒在此對象監視器上等待的所有線程??notifyAll();??}?? }?? //生產者?? class?Producer?extends?Thread{??private?int?neednum;//生產產品的數量??private?Godown?godown;//倉庫??Producer(int?neednum,?Godown?godown)?{??this.neednum?=?neednum;??this.godown?=?godown;??}??public?void?run(){??//生產指定數量的產品??godown.produce(neednum);??}?? }?? //消費者?? class?Consumer?extends?Thread{??private?int?neednum;//消費產品的數量??private?Godown?godown;//倉庫??Consumer(int?neednum,?Godown?godown)?{??this.neednum?=?neednum;??this.godown?=?godown;??}??public?void?run(){??//消費指定數量的產品??godown.consume(neednum);??}?? }??
????????執行結果:
????????說明:
????????對于本例,要說明的是當發現不能滿足生產或者消費條件的時候,調用對象的wait方法,wait方法的作用是釋放當前線程的所獲得的鎖,并調用對象的notifyAll()方法,通知(喚醒)該對象上其他等待線程,使得其繼續執行。這樣,整個生產者、消費者線程得以正確的協作執行。
????????notifyAll() 方法,起到的是一個通知作用,不釋放鎖,也不獲取鎖。只是告訴該對象上等待的線程“可以競爭執行了,都醒來去執行吧”。
????????本例僅僅是生產者消費者模型中最簡單的一種表示,本例中,如果消費者消費的倉儲量達不到滿足,而又沒有生產者,則程序會一直處于等待狀態,這當然是不對的。實際上可以將此例進行修改,修改為,根據消費驅動生產,同時生產兼顧倉庫,如果倉不滿就生產,并對每次最大消費量做個限制,這樣就不存在此問題了,當然這樣的例子更復雜,更難以說明這樣一個簡單模型。
?
Java線程:并發協作-死鎖
? ? ? ? 線程發生死鎖可能性很小,即使看似可能發生死鎖的代碼,在運行時發生死鎖的可能性也是小之又小。
????????發生死鎖的原因一般是兩個對象的鎖相互等待造成的。
????????在《Java線程:線程的同步與鎖》部分,簡述了死鎖的概念與簡單例子,但是所給的例子是不完整的,這里給出一個完整的例子。
/**?*?Java線程:并發協作-死鎖?*/?? public?class?Test?{??public?static?void?main(String[]?args)?{??DeadlockRisk?dead?=?new?DeadlockRisk();??MyThread?t1?=?new?MyThread(dead,?1,?2);??MyThread?t2?=?new?MyThread(dead,?3,?4);??MyThread?t3?=?new?MyThread(dead,?5,?6);??MyThread?t4?=?new?MyThread(dead,?7,?8);??t1.start();??t2.start();??t3.start();??t4.start();??}?? }??class?MyThread?extends?Thread?{??private?DeadlockRisk?dead;??private?int?a,?b;??MyThread(DeadlockRisk?dead,?int?a,?int?b)?{??this.dead?=?dead;??this.a?=?a;??this.b?=?b;??}??@Override??public?void?run()?{??dead.read();??dead.write(a,?b);??}?? }??class?DeadlockRisk?{??private?static?class?Resource?{??public?int?value;??}??private?Resource?resourceA?=?new?Resource();??private?Resource?resourceB?=?new?Resource();??public?int?read()?{??synchronized?(resourceA)?{??System.out.println("read():"?+?Thread.currentThread().getName()??+?"獲取了resourceA的鎖!");??synchronized?(resourceB)?{??System.out.println("read():"?+?Thread.currentThread().getName()??+?"獲取了resourceB的鎖!");??return?resourceB.value?+?resourceA.value;??}??}??}??public?void?write(int?a,?int?b)?{??synchronized?(resourceB)?{??System.out.println("write():"?+?Thread.currentThread().getName()??+?"獲取了resourceA的鎖!");??synchronized?(resourceA)?{??System.out.println("write():"??+?Thread.currentThread().getName()?+?"獲取了resourceB的鎖!");??resourceA.value?=?a;??resourceB.value?=?b;??}??}??}?? }??
????????執行結果:
??
?
總結
以上是生活随笔為你收集整理的Java线程详解(9)-并发协作的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java线程详解(8)-线程的同步
- 下一篇: Java线程详解(10)-volatil