1. 程式人生 > >生產者與消費者案例

生產者與消費者案例

手頭有兩個人(也就是兩個類),一個做存操作,一個做取操作,並且只有當存完或者取完方可進行令一個操作。以此達到迴圈輸出的存取操作。

第一步:先寫測試生產者類與消費者類  和 執行緒操作Msg類

//生產者
public class Product implements Runnable{
    private Msg msg = null; //執行緒操作物件
    public Product (Msg msg){
        super();
        this.msg = msg;
    }
    @override
    public void run(){
        for(int i=0;i<10;i++){
            if(i%2==0){
                   try{
                    this.msg.set("男","胡明明");
                }catch{
                    e.printStackTrace();
                }else{
                    this.msg.set("女","肖體秀");
                }
            }
        }
    
    }

}


//消費者
public class Consumer implements Runnable{
    private Msg msg = null;
     public Consumer (Msg msg){
        super();
        this.msg = msg;
    }
    
    @override
    public void run(){
        for(int i=0;i<10;i++){
            try{
                this.msg.get();
            }catch{
                e.printStackTrance();
            }
        }
    }

}

//執行緒操作Msg類
public class Msg{
    private String title;
    private String content;
    private boolearn flag = true;//true:生產者可以生產,不能取  false:消費者可以取,生產者不能生產
//多個執行緒訪問統一資源。要考慮到資料是否同步的問題,當執行緒進入睡眠或者等待其它執行緒會趁虛而入,所以在方法加上一把鎖

    public synchrnoized void set (String title,String content){
        if(this.flag == false){//存執行緒等待
        System.out.println(Thread.currentThread().getName()+ "進入等待")
        super.wait();
        }
        this.title = title;
        this.content = content;
        this.flag = false;//存完成,改變標識
        System.out.println(Thread.currentThread.getNmae() + "睡眠,並喚醒睡眠或者等待的執行緒")
        super.notify();//喚醒第一個等待的執行緒(取)
    }

    public synchrnoized void get(){
        if(this.flag == true){//取等待
            super.wait();
        }
        System.out.println(Thread.currentThread().getName() + this.title +"-----" +             this.content)
    this.flag = false;//存完成,改變標識
    super.notify();//喚醒第一個等待的執行緒(存)
    }

    public static void main(String[] args){
        Msg msg = new Msg();//例項化物件
        new Thread(msg,"存執行緒1")。start();
        new Thread(msg,"存執行緒2")。start();
        //new Thread(msg,"取執行緒")。start();
    }

}

/**
*實際上這個也很好理解,假設有兩個執行緒,存執行緒和取執行緒(兩個不同的操作類)被cpu呼叫,進入佇列,假
*設存執行緒先被執行**那麼,先走for迴圈第次存(同步,別的執行緒進不來)胡明明,當準備走第1次時,再次進
*行存的操作,發現存不了了,因為要存一次取一次,故將該執行緒進入睡眠狀態,也就數阻塞。所以在外面伺機*已久的取執行緒進來了,進行取得操作,並喚醒其它睡眠或者等待的執行緒(期間存執行緒可能已經被喚醒了,進行*了存的操作)。當再次準備繼續走迴圈時,同樣跟存一樣,也是必須一取一存才可以,由於識別符號的改變,故*取執行緒進入睡眠。以此類推
*/

//當只有存取執行緒的時候確實是交易輸出,但是我加了一個存執行緒,進入死鎖。解析如下:

假設存1存2執行緒分別進入run方法,但是隻能有一個人才能做存操作,假設有幸是存1,那麼存1存完後,存方法被放開了,存1存2都有可能再次做存操作,但是,不管誰做存都做不了,要等到取做完才能做存,即會有兩個存執行緒進入等待狀態,隨後只有當取執行緒喚醒其中一個執行緒後才能進行存的操作,那麼它又將喚醒一個執行緒,那麼到底是喚醒存1還是存2呢?先不管,假設喚醒了存1,那存1又該喚醒誰呢?如果喚醒的是存2呢?那麼取執行緒也就只能睡著,即下一個存執行緒無法解放,兩個存執行緒就只能一直等待著,三個進入死鎖。