多執行緒之生產者消費者
阿新 • • 發佈:2019-02-11
/* * 以生產饅頭,消耗饅頭為例 */ public class ProduceConsume { public static void main(String[] args) { SyncStack ss = new SyncStack();//建造一個裝饅頭的框 Producer p = new Producer(ss);//新建一個生產者,使之持有框 Consume c = new Consume(ss);//新建一個消費者,使之持有同一個框 new Thread(p).start();//新建一個生產者執行緒並啟動 try { Thread.sleep(1000);//造成一個生產執行緒和消費執行緒的時間差,就不會產生沒生產就消費的情況 } catch (InterruptedException e) { e.printStackTrace(); } new Thread(c).start();;//新建一個消費者執行緒並啟動 } } //饅頭類 class SteamBread{ int id;//饅頭編號 SteamBread(int id){ this.id = id; } public String toString(){ //重寫toString方法 return "steamBread:"+id; } } //裝饅頭的框,棧結構 class SyncStack{ int index = 0; SteamBread[] stb = new SteamBread[6];//構造饅頭陣列,相當於饅頭筐,容量是6 //放入框中,相當於入棧 public synchronized void push(SteamBread sb){ while(index==stb.length){//筐滿了,即棧滿, try { this.wait();//讓當前執行緒等待 } catch (InterruptedException e) { e.printStackTrace(); } } this.notify();//喚醒在此物件監視器上等待的單個執行緒,即消費者執行緒 stb[index] = sb; index++; } //從框中拿出,相當於出棧 public synchronized SteamBread pop(){ while(index==0){//筐空了,即棧空 try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } this.notify(); index--;//push第n個之後,index++,使棧頂為n+1,故return之前要減一 return stb[index]; } } //生產者類,實現了Runnable介面,以便於構造生產者執行緒 class Producer implements Runnable{ SyncStack ss = null; Producer(SyncStack ss){ this.ss = ss; } @Override public void run() { // 開始生產饅頭 for(int i=0;i<10;i++){ SteamBread stb = new SteamBread(i); ss.push(stb); System.out.println("生產了"+stb); try { Thread.sleep((int)(Math.random()*1000));//每生產一個饅頭,睡覺隨機秒 } catch (InterruptedException e) { e.printStackTrace(); } } } } //消費者類,實現了Runnable介面,以便於構造消費者執行緒 class Consume implements Runnable{ SyncStack ss = null; public Consume(SyncStack ss) { this.ss = ss; } @Override public void run() { for(int i=0;i<10;i++){//開始消費饅頭 SteamBread stb = ss.pop(); System.out.println("消費了"+stb); try { Thread.sleep((int)(Math.random()*1000));//每消費一個饅頭,睡覺隨機秒。 } catch (InterruptedException e) { e.printStackTrace(); } } } }