爲了支持多線程之間的協作,jdk提供了兩個非常重要的方法線程等待wait()和通知notify()方法,這兩個方法不是Thread類的,而是屬於Object類。
方法的方法簽名:
當一個對象實例調用了wait()方法之後,當前線程就會在這個對象上等待。比如線程A中調用了obj.wait()方法,線程A就會停止繼續執行而轉爲等待狀態,等待狀態持續到其他線程調用了obj.notify()或obj.notifyAll()爲止。
當一個線程調用了obj.wait(),這個線程就會進入obj這個對象的等待隊列中。obj.notify()會在這個對象的等待隊列中隨機選擇一個線程進行通知喚醒;而notifyAll()則是通知喚醒等待線程隊列中所有的線程。
還有就是wait和notify都必須包含在對應的synchronized語句中,無論是wait()還是notify()都需要先獲取目標對象的一個監視器,並且執行之後都會釋放這個監視器,如下圖所示
wait()和notify()的例子:生產者消費者問題,代碼如下
package com.bckj.Thread;
/**
* Created by Admin on 2017/6/12.
*/
//倉庫類
public class Store {
private final int MAX_SIZE; //倉庫的最大容量
private int count; //當前的倉庫數量
public Store(int n){
MAX_SIZE = n;
count = 0;
}
//往倉庫加貨物的方法
public synchronized void add(){ //使用了wait()或notify()方法,需要加上syncronized關鍵字
while(count >= MAX_SIZE){ //否則可能會拋出java.lang.IllegalMonitorStateException
System.out.println("已經滿了");
try{
this.wait();
}catch (InterruptedException e){
e.printStackTrace();
}
}
count++;
//打印當前倉庫的貨物數量
System.out.println(Thread.currentThread().toString()+" put"+count);
//倉庫中已經有東西可以取了,則通知所有的消費者線程來拿
this.notifyAll();
}
//從倉庫拿走貨物的方法
public synchronized void remove(){
while(count <= 0){
System.out.println("空了");
try{
this.wait();
}catch (InterruptedException e){
e.printStackTrace();
}
}
//打印當前倉庫的貨物數量
System.out.println(Thread.currentThread().toString()+" get"+count);
count--;
//倉庫還沒裝滿,通知生產者添加貨物
this.notify();
}
public static void main(String[] args) {
Store s = new Store(5); //創建容量爲5的倉庫
//創建兩個生產者和兩個消費者
Thread pro = new Producer(s);
Thread con = new Consumer(s);
Thread pro2 = new Producer(s);
Thread con2 = new Consumer(s);
pro.setName("producer");
con.setName("consumer");
pro2.setName("producer2");
con2.setName("consumer2");
//啓動各個線程
pro.start();
pro2.start();
con.start();
con2.start();
}
}
class Producer extends Thread{ //生產者線程類
private Store s;
public Producer(Store s){
this.s = s;
}
public void run(){ //線程方法
while(true){ //永久循環
s.add(); //往倉庫加貨物
try{
Thread.sleep(1000);
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
}
class Consumer extends Thread{ //消費者線程類
private Store s;
public Consumer(Store s){
this.s = s;
}
public void run(){ //線程方法
while(true){ //永久循環
s.remove(); //往倉庫取走貨物
try{
Thread.sleep(1500);
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
}
執行結果: