線程通訊(生產者消費者問題)、wait()與notify()方法詳解

1、線程通訊(生產者消費者問題): 
一、線程通信: 一個線程完成了本身的任務時,要通知另一個線程去完成另一個任務。安全

二、經典問題:生產者與消費者問題。 
1)存在線程安全問題:可能出現價格錯亂的狀況,因此要加鎖,而這裏的Product p 對象是惟一的,便可做爲鎖。函數

package sram.thread;
//產品類
class Product{
    String name;  //名字
    double price;  //價格
}
//生產者
class Producer extends Thread{
    Product  p ;    //產品

    public Producer(Product p) {
        this.p  = p ;
    }

    public void run(){
        int i = 0;
        while(true){
            synchronized(p){
                if(i%2==0){
                    p.name = "蘋果";
                    p.price = 6;
                }else{
                    p.name = "香蕉";
                    p.price = 3;
                }
                i++;
                System.out.println("生產了"+p.name+",單價爲"+p.price+"元");
            }
        }
    }
}
//消費者
class Customer extends Thread{
    Product p; 

    public Customer(Product p) {
        this.p = p;
    }
    public void run(){
        while(true){
            synchronized(p){
                System.out.println("消費了"+p.name+"單價爲"+p.price+"元");
            }
        }
    }
}

public class ProAndCust {
    public static void main(String[] args){
        Product p = new Product();
        //建立生產對象
        Producer producer = new Producer(p);
        //建立消費者
        Customer customer = new Customer(p);
        //調用start方法開啓線程
        producer.start();
        customer.start();
    }
}

2)若是我想作到生成一個,消費一個的輸出形式該如何作呢? 
因此這裏引入,線程中的wait()和notify()方法。this

2、wait()與notify()方法詳解 
一、改進版生產者消費者問題:線程

package sram.thread;
//產品類
class Product{
    String name;  //名字
    double price;  //價格
    boolean flag = false; //產品是否生產完畢的標識,默認狀況是沒有生產完成。
}
//生產者
class Producer extends Thread{
    Product  p ;    //產品

    public Producer(Product p) {
        this.p  = p ;
    }

    public void run(){
        int i = 0;
        while(true){
            synchronized(p){
                if(p.flag==false){
                    if(i%2==0){
                        p.name = "蘋果";
                        p.price = 6;
                    }else{
                        p.name = "香蕉";
                        p.price = 3;
                    }
                    i++;
                    System.out.println("生產了"+p.name+",單價爲"+p.price+"元");
                    p.flag = true;
                    p.notify();//喚醒消費者去消費
                }else{
                    //已經生產完畢,等待消費者先去消費
                    try {
                        //生產者等待
                        p.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}
//消費者
class Customer extends Thread{
    Product p; 

    public Customer(Product p) {
        this.p = p;
    }
    public void run(){
        while(true){
            synchronized(p){
                if(p.flag==true){//產品已經生產完畢
                    System.out.println("消費了"+p.name+"單價爲"+p.price+"元");
                    p.flag = false;
                    p.notify();//喚醒生產者去生產
                }else{
                    //產品尚未生產,應該等待生產者先生產。
                    try {
                        p.wait();//消費者等待
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}

public class ProAndCust {
    public static void main(String[] args){
        Product p = new Product();
        //建立生產對象
        Producer producer = new Producer(p);
        //建立消費者
        Customer customer = new Customer(p);
        //調用start方法開啓線程
        producer.start();
        customer.start();
    }
}

二、API詳解: 
wait(): 等待 若是線程執行了wait方法,那麼該線程會進入等待的狀態,等待狀態下的線程必需要被其餘線程調用notify方法才能喚醒。 
notify(): 喚醒 喚醒線程池等待線程其中的一個。 
notifyAll() : 喚醒線程池全部等待線程。code

三、wait與notify方法要注意的事項: 
1)wait方法與notify方法是屬於Object對象的。 
分析:這兩個方法是由鎖對象調用的,而所對象能夠是任意類型的。 
2)wait方法與notify方法必需要在同步代碼塊或者是同步函數中才能使用。 
分析:只有同步代碼塊與同步函數中才會用到鎖。 
3)wait方法與notify方法必須要由鎖對象調用。 
分析:見圖示。對象

相關文章
相關標籤/搜索