本文來自 http://blog.csdn.net/liuxian13183/ ,引用必須注明出處!
上一講我們讓消費者和生産者都各停1毫秒,實際上大多并不是這樣的。第二講,我們講一個極端的例子和一個正常的例子,假設您已經看過上一講,我們隻改變Consumer和Producer,來看結果。 Java生産者與消費者(上)名詞解釋
wait:目前線程不運作,處理等待狀态,等待notify;是以也不會往下執行。
您可能會有疑問前例中的為什麼要用while循環而非if語句?
主要是防止多線程操作時,例桌子已經占滿,兩個生産線程均處理等待狀态,但消費線程通過notifyAll打開其等待狀态,就造成生産過量的蛋糕,而導緻生産消費模式失敗,是以不能用if語句。
sleep:暫停目前線程若幹時間,之後繼續運作
Special Sample:生産者和消費者均不加sleep
Result:
Produce1 produce:1 Produce2 produce:2 Produce1 produce:3 Produce1 produce:4 Produce1 produce:5 Produce1 begin to wait ! Consumer1 consume:5 Consumer1 consume:4 Consumer1 consume:3 Consumer1 consume:2 Consumer1 consume:1 Consumer1 begin to wait ! Produce1 stop waiting ! Produce1 produce:1
Produce1 produce:2 Produce2 produce:3 Produce2 produce:4 Produce2 produce:5 Produce2 begin to wait ! Consumer2 consume:5 Consumer2 consume:4 Consumer2 consume:3 Consumer2 consume:2 Consumer2 consume:1 Consumer2 begin to wait ! Produce2 stop waiting ! Produce2 produce:1 Produce2 produce:2 Produce2 produce:3 Produce2 produce:4 Produce2 produce:5 Produce2 begin to wait ! Produce1 begin to wait ! Consumer1 stop waiting ! Consumer1 consume:5 Consumer1 consume:4 Consumer1 consume:3 Consumer1 consume:2 Consumer1 consume:1 Consumer1 begin to wait ! Produce1 stop waiting ! Produce1 produce:1 Produce1 produce:2 Produce1 produce:3 Produce1 produce:4 Produce1 produce:5 Produce1 begin to wait ! Produce2 stop waiting ! Produce2 begin to wait ! Consumer2 stop waiting ! Consumer2 consume:5 Consumer2 consume:4 Consumer2 consume:3 Consumer2 consume:2 Consumer2 consume:1 Consumer2 begin to wait ! Produce2 stop waiting ! Produce2 produce:1 Produce2 produce:2 Produce2 produce:3 Produce2 produce:4 Produce2 produce:5 Produce2 begin to wait ! Produce1 stop waiting ! Produce1 begin to wait ! Consumer1 stop waiting ! Consumer1 consume:5 Consumer1 consume:4 Consumer1 consume:3 Consumer1 consume:2 Consumer1 consume:1 Consumer1 begin to wait ! Produce1 stop waiting ! Produce1 produce:1 Produce1 stop at last !
解析:例子很極端,生産和消費均兩個線程,A線程在工作時B在等待;
A生産線程生産,B生産線程等待直到A生産完;
A消費線程消費,B消費線程等待直到A消費完;
B生産線程生産,A生産線程等待直到A生産完;
B消費線程消費,A消費線程等待直到A消費完;
……
這樣一個循環,失去多線程的意義所在(變成了單線程)!
正常的例子:生産可能隻需要1毫秒,消費需要2毫秒
Produce1 produce:1 Consumer1 consume:1 Consumer2 begin to wait !//此時Consumer2檢測到count為0,是以等待 Produce2 produce:1 Consumer2 stop waiting !//此時Consumer2檢測到count已經大于0,是以打開 Consumer2 consume:1 Produce1 produce:1//看,生産與消費是無序的。兩者分開,不管你在不在生産,我都要消費,隻要蛋糕還有; Produce2 produce:2//不管你消費不消費,隻要桌子還有空的;它們兩個均對一種情況負責:桌子和蛋糕形成的映射關系! Consumer2 consume:2 Consumer1 consume:1 Produce2 produce:1 Produce1 produce:2 Produce2 produce:3 Produce1 produce:4 Consumer1 consume:4 Consumer2 consume:3 Produce1 produce:3 Produce2 produce:4 Produce2 produce:5 Produce1 begin to wait ! Consumer1 consume:5 Produce1 stop waiting ! Produce1 produce:5 Produce2 begin to wait ! Consumer2 consume:5 Produce2 stop waiting ! Produce2 produce:5 Produce2 begin to wait ! Produce1 begin to wait ! Consumer2 consume:5 Produce1 stop waiting ! Produce1 produce:5 Produce2 stop waiting ! Produce2 begin to wait ! Consumer1 consume:5 Produce2 stop waiting ! Produce2 produce:5 Produce1 begin to wait ! Produce2 begin to wait ! Consumer1 consume:5 Consumer1 stop at last !
解析:這次我讓執行25次即退出虛拟機。
大家可以看到,本次兩個生産線程和兩個消費線程,在生産和消費的時候都是無序的,無論你要不要停,我都要工作,不能讓一個線程一直抓住鎖不放,其實這才是多線程本質。
代碼如下:
Producer:
消費者:public class Producer extends Thread { Table table; String threadName; public Producer(String string, Table table) { // TODO Auto-generated constructor stub this.table = table; this.threadName = string; this.setName(threadName); } @Override public void run() { // TODO Auto-generated method stub super.run(); try { while (true) { table.produce(threadName); sleep(1); } } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
public class Consumer extends Thread { Table table; String threadName; public Consumer(String string, Table table) { // TODO Auto-generated constructor stub this.table = table; this.threadName = string; this.setName(threadName); } @Override public void run() { // TODO Auto-generated method stub super.run(); try { while (true) { table.consume(threadName); sleep(2); } } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }