生產者消費者問題是線程模型中的經典問題:生產者和消費者在同一時間段內共用同一存儲空間,生產者向空間裏生產數據,而消費者取走數據。多線程
這裏實現以下狀況的生產--消費模型:this
生產者不斷交替地生產兩組數據「姓名--1 --> 內容--1」,「姓名--2--> 內容--2」,消費者不斷交替地取得這兩組數據,這裏的「姓名--1」和「姓名--2」模擬爲數據的名稱,「內容--1 」和「內容--2 」模擬爲數據的內容。線程
因爲本程序中牽扯到線程運行的不肯定性,所以可能會出現如下問題:對象
一、假設生產者線程剛向數據存儲空間添加了數據的名稱,尚未加入該信息的內容,程序就切換到了消費者線程,消費者線程將把信息的名稱和上一個信息的內容聯繫在一塊兒;blog
二、生產者生產了若干次數據,消費者纔開始取數據,或者是,消費者取完一次數據後,還沒等生產者放入新的數據,又重複取出了已取過的數據。get
問題1很明顯要靠同步來解決,問題2則須要線程間通訊,生產者線程放入數據後,通知消費者線程取出數據,消費者線程取出數據後,通知生產者線程生產數據,這裏用wait/notify機制來實現。同步
詳細的實現代碼以下:it
1 class Info{ // 定義信息類 2 private String name = "name";//定義name屬性,爲了與下面set的name屬性區別開 3 private String content = "content" ;// 定義content屬性,爲了與下面set的content屬性區別開 4 private boolean flag = true ; // 設置標誌位,初始時先生產 5 public synchronized void set(String name,String content){ 6 while(!flag){ 7 try{ 8 super.wait() ; 9 }catch(InterruptedException e){ 10 e.printStackTrace() ; 11 } 12 } 13 this.setName(name) ; // 設置名稱 14 try{ 15 Thread.sleep(300) ; 16 }catch(InterruptedException e){ 17 e.printStackTrace() ; 18 } 19 this.setContent(content) ; // 設置內容 20 flag = false ; // 改變標誌位,表示能夠取走 21 super.notify(); 22 } 23 public synchronized void get(){ 24 while(flag){ 25 try{ 26 super.wait() ; 27 }catch(InterruptedException e){ 28 e.printStackTrace() ; 29 } 30 } 31 try{ 32 Thread.sleep(300) ; 33 }catch(InterruptedException e){ 34 e.printStackTrace() ; 35 } 36 System.out.println(this.getName() + 37 " --> " + this.getContent()) ; 38 flag = true ; // 改變標誌位,表示能夠生產 39 super.notify(); 40 } 41 public void setName(String name){ 42 this.name = name ; 43 } 44 public void setContent(String content){ 45 this.content = content ; 46 } 47 public String getName(){ 48 return this.name ; 49 } 50 public String getContent(){ 51 return this.content ; 52 } 53 } 54 class Producer implements Runnable{ // 經過Runnable實現多線程 55 private Info info = null ; // 保存Info引用 56 public Producer(Info info){ 57 this.info = info ; 58 } 59 public void run(){ 60 boolean flag = true ; // 定義標記位 61 for(int i=0;i<10;i++){ 62 if(flag){ 63 this.info.set("姓名--1","內容--1") ; // 設置名稱 64 flag = false ; 65 }else{ 66 this.info.set("姓名--2","內容--2") ; // 設置名稱 67 flag = true ; 68 } 69 } 70 } 71 } 72 class Consumer implements Runnable{ 73 private Info info = null ; 74 public Consumer(Info info){ 75 this.info = info ; 76 } 77 public void run(){ 78 for(int i=0;i<10;i++){ 79 this.info.get() ; 80 } 81 } 82 } 83 public class ThreadCaseDemo03{ 84 public static void main(String args[]){ 85 Info info = new Info(); // 實例化Info對象 86 Producer pro = new Producer(info) ; // 生產者 87 Consumer con = new Consumer(info) ; // 消費者 88 new Thread(pro).start() ; 89 //啓動了生產者線程後,再啓動消費者線程 90 try{ 91 Thread.sleep(500) ; 92 }catch(InterruptedException e){ 93 e.printStackTrace() ; 94 } 95 96 new Thread(con).start() ; 97 } 98 }
執行結果以下:io
另外,在run方法中,兩者循環的次數要相同,不然,當一方的循環結束時,另外一方的循環依然繼續,它會阻塞在wait()方法處,而等不到對方的notify通知class