1. 程式人生 > >java wait用法詳解

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();
			}
		}
	}
}

參考:

http://www.jb51.net/article/40746.htm