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方法必須要由鎖對象調用。
分析:見圖示。對象