java wait用法詳解
一、wait(), notify(), notifyAll()等方法介紹
1.wait()的作用是讓當前執行緒進入等待狀態,同時,wait()也會讓當前執行緒釋放它所持有的鎖。“直到其他執行緒呼叫此物件的 notify() 方法或 notifyAll() 方法”,當前執行緒被喚醒(進入“就緒狀態”)
2.notify()和notifyAll()的作用,則是喚醒當前物件上的等待執行緒;notify()是喚醒單個執行緒,而notifyAll()是喚醒所有的執行緒。
3.wait(long timeout)讓當前執行緒處於“等待(阻塞)狀態”,“直到其他執行緒呼叫此物件的notify()方法或
notifyAll()
二、wait 的用法詳解(這裡的t1是一個執行緒(鎖))
// main(主執行緒)
synchronized(t1) {
try {
t1.start();
t1.wait();
} catch(InterruptedException e) {
e.printStackTrace();
}
}
// 在 t1 執行緒中喚醒主執行緒
synchronized (this) { //這裡的 this 為 t1
this.notify();
}
注:
1、synchronized(t1)鎖定t1(獲得t1的監視器)
2、synchronized(t1)這裡的鎖定了t1,那麼wait需用t1.wait()(釋放掉t1)
3、因為wait需釋放鎖,所以必須在synchronized中使用(沒有鎖定則麼可以釋放?沒有鎖時使用會丟擲IllegalMonitorStateException(正在等待的物件沒有鎖))
4. notify也要在synchronized使用,應該指定物件,t1. notify(),通知t1物件的等待池裡的執行緒使一個執行緒進入鎖定池,然後與鎖定池中的執行緒爭奪鎖。那麼為什麼要在synchronized使用呢? t1. notify()需要通知一個等待池中的執行緒,那麼這時我們必須得獲得t1的監視器(需要使用synchronized),才能對其操作,t1. notify()程式只是知道要對t1操作,但是是否可以操作與是否可以獲得t1鎖關聯的監視器有關。
5. synchronized(),wait,notify() 物件一致性
6. 在while迴圈裡而不是if語句下使用wait(防止虛假喚醒spurious wakeup)
三、證明wait使當前執行緒等待
class ThreadA extends Thread{
public ThreadA(String name) {
super(name);
}
public void run() {
synchronized (this) {
try {
Thread.sleep(1000); // 使當前線阻塞 1 s,確保主程式的 t1.wait(); 執行之後再執行 notify()
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+" call notify()");
// 喚醒當前的wait執行緒
this.notify();
}
}
}
public class WaitTest {
public static void main(String[] args) {
ThreadA t1 = new ThreadA("t1");
synchronized(t1) {
try {
// 啟動“執行緒t1”
System.out.println(Thread.currentThread().getName()+" start t1");
t1.start();
// 主執行緒等待t1通過notify()喚醒。
System.out.println(Thread.currentThread().getName()+" wait()");
t1.wait(); // 不是使t1執行緒等待,而是當前執行wait的執行緒等待
System.out.println(Thread.currentThread().getName()+" continue");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
四、wait(long timeout)超時被喚醒
class ThreadA extends Thread{
public ThreadA(String name) {
super(name);
}
public void run() {
System.out.println(Thread.currentThread().getName() + " run ");
// 死迴圈,不斷執行。
while(true){;} // 這個執行緒與主執行緒無關,無 synchronized
}
}
public class WaitTimeoutTest {
public static void main(String[] args) {
ThreadA t1 = new ThreadA("t1");
synchronized(t1) {
try {
// 啟動“執行緒t1”
System.out.println(Thread.currentThread().getName() + " start t1");
t1.start();
// 主執行緒等待t1通過notify()喚醒 或 notifyAll()喚醒,或超過3000ms延時;然後才被喚醒。
System.out.println(Thread.currentThread().getName() + " call wait ");
t1.wait(3000);
System.out.println(Thread.currentThread().getName() + " continue");
t1.stop();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}