Java—wait 方法和notify方法
阿新 • • 發佈:2018-12-09
1. wait()—痴漢方法
wait()方法就是使執行緒停止執行,會釋放物件鎖。
wait()方法是從執行態回阻塞態。
notifi( ) 方法是從阻塞態回執行態。
- wait()方法會使當前執行緒呼叫該方法後進行等待,並且將該執行緒置入鎖物件的等待佇列中,直到接到通知或被中斷為止。
- wait()方法只能在同步方法或同步程式碼塊中呼叫,如果呼叫wait()時沒有適當的鎖,會丟擲異常。
- wait()方法執行後,當前執行緒釋放鎖,其他執行緒可以競爭該鎖。
- wait()之後的執行緒繼續執行有兩種方法:
- 呼叫該物件的notify()方法喚醒等待執行緒。
- 執行緒等待時呼叫interrupt()中斷該執行緒。
wait(long time) :如果到了預計時間還未被喚醒,執行緒將繼續執行。
class MyThread implements Runnable{ private Object object; private boolean flag; public MyThread(Object object, boolean flag) { this.object = object; this.flag = flag; } public void waitMethod() { synchronized (object) { System.out.println("wait方法開始..." + Thread.currentThread().getName()); try { object.wait(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("wait方法結束..." + Thread.currentThread().getName()); } } public void notifyMethod(){ synchronized (object) { System.out.println("notify方法開始..." + Thread.currentThread().getName()); object.notify(); System.out.println("notify方法結束..." + Thread.currentThread().getName()); } } public void run(){ if(flag){ this.waitMethod(); }else{ this.notifyMethod(); } } } public class Object { public static void main(String[] args)throws InterruptedException{ Object obj = new Object(); MyThread thread1 = new MyThread(obj,true); MyThread thread2 = new MyThread(obj,false); Thread waitThread = new Thread(thread1,"等待執行緒"); Thread notifyThread = new Thread(thread2,"喚醒執行緒"); waitThread.start(); Thread.sleep(1000); notifyThread.start(); } } 執行結果: wait方法開始...等待執行緒 notify方法開始...喚醒執行緒 notify方法結束...喚醒執行緒 wait方法結束...等待執行緒
2. notify()方法
- notify()方法必須在同步方法或同步程式碼塊中呼叫,用來喚醒等待在該物件上的執行緒,如果有多個執行緒等待,則任意挑選一個執行緒喚醒。
- notify()方法執行後,喚醒執行緒不會立刻釋放鎖,要等喚醒執行緒全部執行完畢後才釋放物件鎖。
class MyThread implements Runnable{ private Object object; private boolean flag; public MyThread(Object object, boolean flag) { this.object = object; this.flag = flag; } public void waitMethod() { synchronized (object) { System.out.println("wait方法開始..." + Thread.currentThread().getName()); try { object.wait(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("wait方法結束..." + Thread.currentThread().getName()); } } public void notifyMethod(){ synchronized (object) { System.out.println("notify方法開始..." + Thread.currentThread().getName()); object.notify(); System.out.println("notify方法結束..." + Thread.currentThread().getName()); } } public void run(){ if(flag){ this.waitMethod(); }else{ this.notifyMethod(); } } } public class Object { public static void main(String[] args)throws InterruptedException{ Object obj = new Object(); MyThread thread1 = new MyThread(obj,true); MyThread thread2 = new MyThread(obj,false); for(int i = 0;i<5;i++) { Thread threadi = new Thread(thread1, "等待執行緒"+i); threadi.start(); } Thread notifyThread = new Thread(thread2,"喚醒執行緒"); Thread.sleep(1000); notifyThread.start(); } } wait方法開始...等待執行緒0 wait方法開始...等待執行緒1 wait方法開始...等待執行緒2 wait方法開始...等待執行緒3 wait方法開始...等待執行緒4 notify方法開始...喚醒執行緒 notify方法結束...喚醒執行緒 wait方法結束...等待執行緒0 //當有多個執行緒同時等待時,notify方法任意挑選一個喚醒。
wait()和notify()均用於同步方法或同步程式碼塊並且必須是內建鎖。
3. notifyAll()
喚醒所有在該物件上等待的執行緒。
class MyThread implements Runnable{
private Object object;
private boolean flag;
public MyThread(Object object, boolean flag) {
this.object = object;
this.flag = flag;
}
public void waitMethod() {
synchronized (object) {
System.out.println("wait方法開始..." + Thread.currentThread().getName());
try {
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("wait方法結束..." + Thread.currentThread().getName());
}
}
public void notifyMethod(){
synchronized (object) {
System.out.println("notify方法開始..." + Thread.currentThread().getName());
object.notifyAll();
System.out.println("notify方法結束..." + Thread.currentThread().getName());
}
}
public void run(){
if(flag){
this.waitMethod();
}else{
this.notifyMethod();
}
}
}
public class Object {
public static void main(String[] args)throws InterruptedException{
Object obj = new Object();
MyThread thread1 = new MyThread(obj,true);
MyThread thread2 = new MyThread(obj,false);
for(int i = 0;i<5;i++) {
Thread threadi = new Thread(thread1, "等待執行緒"+i);
threadi.start();
}
Thread notifyThread = new Thread(thread2,"喚醒執行緒");
Thread.sleep(1000);
notifyThread.start();
}
}
執行結果:
wait方法開始...等待執行緒0
wait方法開始...等待執行緒1
wait方法開始...等待執行緒2
wait方法開始...等待執行緒3
wait方法開始...等待執行緒4
notify方法開始...喚醒執行緒
notify方法結束...喚醒執行緒
wait方法結束...等待執行緒4
wait方法結束...等待執行緒3
wait方法結束...等待執行緒2
wait方法結束...等待執行緒1
wait方法結束...等待執行緒0
4.執行緒阻塞
- 呼叫sleep()方法,主動放棄佔有的CPU,不會釋放物件鎖。
- 呼叫阻塞式IO方法(read()、write()),在該方法返回前,執行緒阻塞。
- 執行緒試圖獲取一個monitor,但該monitor被其他執行緒所持有導致阻塞。
- 執行緒等待某個通知,即呼叫wait(),釋放物件鎖。
- 呼叫執行緒suspend(),將執行緒掛起,容易導致死鎖,已被廢棄。
這五個執行緒會從執行狀態到阻塞狀態。
5. monitor 的兩個佇列
每個monitor都有兩個佇列,一個稱為同步佇列,一個稱為等待佇列。
- 同步佇列中存放了因為競爭monitor失敗導致阻塞的執行緒,這些執行緒等待CPU排程再次競爭鎖。
- 等待佇列存放所有呼叫wait()方法導致執行緒等待的執行緒,喚醒後進入同步佇列競爭鎖。