Java—多線程6 生產和消費者模型
生產者消費者模型
生產者和消費者不直接通信 而是通過一個阻塞隊列通信
wait()方法
使得當前線程立刻停止運行,處於等待狀態,並將當前狀態置入鎖對象的等待隊列中,直到被通知(notify())或中斷爲止。
使用條件:只能在同步方法或者同步代碼塊中使用,必須是內建鎖。
wait()調用後立刻釋放對象鎖。
1.一直等,直到被喚醒或者中斷。
public final void wait() throws InterruptedException {
wait(0);
}
2.超時等待。若在規定時間內未被喚醒,則線程退出
public final native void wait(long timeout) throws InterruptedException;
3.在2的基礎上進行納秒級別的參數傳入
public final void wait(long timeout, int nanos) throws InterruptedException
notify()
喚醒處於等待中的線程
使用條件:notify必須在同步方法或者同步代碼塊中調用,用來喚醒等待該對象的其他線程,如果有多個線程在等待,隨機挑選一個喚醒(但是具體喚醒哪一個是版本決定的,JDK8 默認是等待隊列的第一個)
public final native void notify();
notify方法調用後不會立刻釋放對象鎖,要等到當前線程執行完後釋放對象鎖。
wait和 notify必須操作的是統一個對象
class MyThread implements Runnable{
private boolean flag;
private Object obj;
public MyThread(boolean flag, Object obj) {
this.flag = flag;
this.obj = obj;
}
public void waitMethod() throws InterruptedException {
synchronized (obj){
System.out.println(Thread.currentThread().getName()+"開始");
obj.wait();
System.out.println(Thread.currentThread().getName()+"結束");
}
}
public void notifyMethod(){
synchronized (obj){
System.out.println(Thread.currentThread().getName()+"開始");
obj.notify();
System.out.println(Thread.currentThread().getName()+"結束");
}
}
@Override
public void run() {
if(flag){
try {
waitMethod();
} catch (InterruptedException e) {
e.printStackTrace();
}
}else{
notifyMethod();
}
}
}
public class Test{
public static void main(String[] args) throws InterruptedException {
Object obj=new Object();
MyThread mt1=new MyThread(true,obj);
MyThread mt2=new MyThread(false,obj);
new Thread(mt1,"wait").start();
Thread.sleep(1000);
new Thread(mt2,"notify").start();
}
}
運行結果:
wait開始
notify開始
notify結束
wait結束
可以看出,wait不喚醒會一直等下去,但是notify()調用後不會立刻釋放對象鎖,而是要到當前線程執行完才叫鎖。
線程由運行態到阻塞態
1.調用sleep,立刻交出CPU,不釋放鎖
2.線程調用阻塞時IO(BIO)方法
3.線程獲取鎖失敗進入阻塞狀態
4,線程調用wait()
5.線程調用suspend(),將線程掛起
每個鎖對象都有兩個隊列。
1.同步隊列,存儲獲取鎖失敗的線程。
2.另一個稱爲等待隊列存儲調用wait()等待線程。
將線程喚醒實際上是將等待隊列的線程移到同步隊列中競爭鎖。