前言
消費者生產者模式是java中多線程的典型模式,它牽涉到java中多個線程交互的一些方式。下面根據一些典型的實現來說明;
一、方式1
該方式源碼出處為:http://eric-619.iteye.com/blog/693681
(有一篇講解多線程的非常有名的博客,建議初學多線程的朋友多關注一下,總結網址為:http://lavasoft.blog.51cto.com/62575/27069,順便感謝一下這些大牛們為吾等小白掃盲!)
生產者-消費者模型准確說應該是“生產者-消費者-倉儲”模型,離開了倉儲,生產者消費者模型就顯得沒有說服力了。
對於此模型,應該明確一下幾點:
1、生產者僅僅在倉儲未滿時候生產,倉滿則停止生產。
2、消費者僅僅在倉儲有產品時候才能消費,倉空則等待。
3、當消費者發現倉儲沒產品可消費時候會通知生產者生產。
4、生產者在生產出可消費產品時候,應該通知等待的消費者去消費
此模型將要結合java.lang.Object的wait與notify、notifyAll方法來實現以上的需求。這是非常重要的。
生產者和消費者通過共享內存的方式進行通信;它們共享的內存是:SyncStack對象;生產者通過SyncStack的同步方法pop向其中添加對象;消費者通過SyncStack的同步方法pop方法在SyncStack對象中獲取對象;這是對象間共享內存(或共享數據區域)的方式進行的通信。
關鍵點詳解:
其中的關鍵是共享內存區域中的兩個同步方法,及同步方法中wait()方法的調用;同步保證了對象只能被一個線程占用,wait保證了當線程在等待的過程中釋放自己的鎖,使得其它對象有機會獲得對象的鎖;
缺點:
在多個線程進行操作時(有較多生產者和消費者時),使用notifyAll方法會造成不必要進行喚醒的方法進行線程的調度,從而導致不必要的時間花銷;
比如一個消費者線程調用了notifyAll(),則會喚醒其它消費者,但是其本意是喚醒生產者來制造物品;由此可見,該方法並沒有進行定點的通知。
/* * 生產者消費者問題其含義就是先生產出了產品,才能拉出去讓消費者購買 * 1、多個線程數據共享區域化思想! * 2、生產者消費者 * * 二、synchronized加鎖: * */ public class ProCon{ //主方法 public static void main(String[] args){ SyncStack stack = new SyncStack(); Consumer p = new Consumer(stack); Producer c = new Producer(stack); new Thread(p).start(); new Thread(c).start(); } } class Producer implements Runnable{ //生產者 private SyncStack stack; public Producer(SyncStack stack){ this.stack = stack; } public void run(){ for (int i = 0; i < stack.pro().length; i++){ String product = "產品"+i; stack.push(product); System.out.println("生產了: "+product); try{ Thread.sleep(200); }catch(InterruptedException e) { e.printStackTrace(); } } } } class Consumer implements Runnable{ //消費者 private SyncStack stack; public Consumer(SyncStack stack) { this.stack = stack; } public void run(){ for(int i = 0; i < stack.pro().length; i++){ String product = stack.pop(); System.out.println("消費了: "+product); try{ Thread.sleep(1000); }catch(InterruptedException e){ e.printStackTrace(); } } } } class SyncStack{ // 此類是(本質上:共同訪問的)共享數據區域 private String[] str = new String[10]; private int index; public synchronized void push(String sst){ //供生產者調用 if(index == sst.length()){ try{ wait(); }catch(InterruptedException e){ e.printStackTrace(); } } this.notify(); //喚醒在此對象監視器上等待的單個線程 str[index] = sst; index++; } public synchronized String pop(){ //供消費者調用 if(index == 0){ try{ wait(); }catch (InterruptedException e){ e.printStackTrace(); } } notify(); index--; String product = str[index]; return product; } public String[] pro(){ //就是定義一個返回值為數組的方法,返回的是一個String[]引用 return str; //這是一個String[]引用 } }