java多線程之消費者生產者模式 – JAVA編程語言程序開發技術文章

/*@author shijin
* 生產者與消費者模型中,要保證以下幾點:
* 1 同一時間內隻能有一個生產者生產     生產方法加鎖sychronized
* 2 同一時間內隻能有一個消費者消費     消費方法加鎖sychronized
* 3 生產者生產的同時消費者不能消費     生產方法加鎖sychronized
* 4 消費者消費的同時生產者不能生產     消費方法加鎖sychronized
* 5 共享空間空時消費者不能繼續消費     消費前循環判斷是否為空,空的話將該線程wait,釋放鎖允許其他同步方法執行
* 6 共享空間滿時生產者不能繼續生產     生產前循環判斷是否為滿,滿的話將該線程wait,釋放鎖允許其他同步方法執行   
*/ 
 
//主類 
class  ProducerConsumer 

    public static void main(String[] args)  
    { 
        StackBasket s = new StackBasket(); 
        Producer p = new Producer(s); 
        Consumer c = new Consumer(s); 
        Thread tp = new Thread(p); 
        Thread tc = new Thread(c); 
        tp.start(); 
        tc.start(); 
    } 

 
// 
class Mantou 

    private int id; 
     
    Mantou(int id){ 
        this.id = id; 
    } 
 
    public String toString(){ 
        return "Mantou :" + id; 
    } 

 
//共享棧空間 
class StackBasket 

    Mantou sm[] = new Mantou[6]; 
    int index = 0; 
     
    /** 
    * show 生產方法.
    * show 該方法為同步方法,持有方法鎖;
    * show 首先循環判斷滿否,滿的話使該線程等待,釋放同步方法鎖,允許消費;
    * show 當不滿時首先喚醒正在等待的消費方法,但是也隻能讓其進入就緒狀態,
    * show 等生產結束釋放同步方法鎖後消費才能持有該鎖進行消費
    * @param m 元素
    * @return 沒有返回值 
    */  
 
    public synchronized void push(Mantou m){ 
        try{ 
            while(index == sm.length){ 
                System.out.println("!!!!!!!!!生產滿瞭!!!!!!!!!"); 
                this.wait(); 
            } 
            this.notify(); 
        }catch(InterruptedException e){ 
            e.printStackTrace(); 
        }catch(IllegalMonitorStateException e){ 
            e.printStackTrace(); 
        } 
         
        sm[index] = m; 
        index++; 
        System.out.println("生產瞭:" + m + " 共" + index + "個饅頭"); 
    } 
 
    /** 
    * show 消費方法
    * show 該方法為同步方法,持有方法鎖
    * show 首先循環判斷空否,空的話使該線程等待,釋放同步方法鎖,允許生產;
    * show 當不空時首先喚醒正在等待的生產方法,但是也隻能讓其進入就緒狀態
    * show 等消費結束釋放同步方法鎖後生產才能持有該鎖進行生產
    * @param b true 表示顯示,false 表示隱藏 
    * @return 沒有返回值 
    */  
    public synchronized Mantou pop(){ 
        try{ 
            while(index == 0){ 
                System.out.println("!!!!!!!!!消費光瞭!!!!!!!!!"); 
                this.wait(); 
            } 
            this.notify(); 
        }catch(InterruptedException e){ 
            e.printStackTrace(); 
        }catch(IllegalMonitorStateException e){ 
            e.printStackTrace(); 
        } 
        index–; 
        System.out.println("消費瞭:———" + sm[index] + " 共" + index + "個饅頭"); 
        return sm[index]; 
    } 

 
class Producer implements Runnable 

    StackBasket ss = new StackBasket(); 
    Producer(StackBasket ss){ 
        this.ss = ss; 
    } 
 
    /** 
    * show 生產進程. 
    */  
    public void run(){ 
        for(int i = 0;i < 20;i++){ 
            Mantou m = new Mantou(i); 
            ss.push(m); 
//          System.out.println("生產瞭:" + m + " 共" + ss.index + "個饅頭"); 
//          在上面一行進行測試是不妥的,對index的訪問應該在原子操作裡,因為可能在push之後此輸出之前又消費瞭,會產生輸出混亂 
            try{ 
                Thread.sleep((int)(Math.random()*500)); 
            }catch(InterruptedException e){ 
                e.printStackTrace(); 
            } 
        } 
    } 

 
class Consumer implements Runnable 

    StackBasket ss = new StackBasket(); 
    Consumer(StackBasket ss){ 
        this.ss = ss; 
    } 
 
    /** 
    * show 消費進程.
    */  
    public void run(){ 
        for(int i = 0;i < 20;i++){ 
            Mantou m = ss.pop(); 
//          System.out.println("消費瞭:———" + m + " 共" + ss.index + "個饅頭"); 
//  同上  在上面一行進行測試也是不妥的,對index的訪問應該在原子操作裡,因為可能在pop之後此輸出之前又生產瞭,會產生輸出混亂 
            try{ 
                Thread.sleep((int)(Math.random()*1000)); 
            }catch(InterruptedException e){ 
                e.printStackTrace(); 
            } 
        } 
    } 

摘自 shijinupc的專欄

發佈留言