java wait()方法用法詳解

一、wait(), notify(), notifyAll()等方法介紹

1.wait()的作用是讓當(dāng)前線程進(jìn)入等待狀態(tài),同時,wait()也會讓當(dāng)前線程釋放它所持有的鎖。“直到其他線程調(diào)用此對象的 notify() 方法或 notifyAll() 方法”,當(dāng)前線程被喚醒(進(jìn)入“就緒狀態(tài)”)

2.notify()和notifyAll()的作用,則是喚醒當(dāng)前對象上的等待線程;notify()是喚醒單個線程,而notifyAll()是喚醒所有的線程。

3.wait(long timeout)讓當(dāng)前線程處于“等待(阻塞)狀態(tài)”,“直到其他線程調(diào)用此對象的notify()方法或 notifyAll() 方法,或者超過指定的時間量”,當(dāng)前線程被喚醒(進(jìn)入“就緒狀態(tài)”)。

二、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的監(jiān)視器)

2、synchronized(t1)這里的鎖定了t1,那么wait需用t1.wait()(釋放掉t1)

3、因為wait需釋放鎖,所以必須在synchronized中使用(沒有鎖定則么可以釋放?沒有鎖時使用會拋出IllegalMonitorStateException(正在等待的對象沒有鎖))

4. notify也要在synchronized使用,應(yīng)該指定對象,t1. notify(),通知t1對象的等待池里的線程使一個線程進(jìn)入鎖定池,然后與鎖定池中的線程爭奪鎖。那么為什么要在synchronized使用呢? t1. notify()需要通知一個等待池中的線程,那么這時我們必須得獲得t1的監(jiān)視器(需要使用synchronized),才能對其操作,t1. notify()程序只是知道要對t1操作,但是是否可以操作與是否可以獲得t1鎖關(guān)聯(lián)的監(jiān)視器有關(guān)。

5. synchronized(),wait,notify() 對象一致性

6. 在while循環(huán)里而不是if語句下使用wait(防止虛假喚醒spurious wakeup)

三、證明wait使當(dāng)前線程等待

class ThreadA extends Thread{
    public ThreadA(String name) {
        super(name);
    }
    public void run() {
        synchronized (this) {
            try {                       
                Thread.sleep(1000); //  使當(dāng)前線阻塞 1 s,確保主程序的 t1.wait(); 執(zhí)行之后再執(zhí)行 notify()
            } catch (Exception e) {
                e.printStackTrace();
            }           
            System.out.println(Thread.currentThread().getName()+" call notify()");
            // 喚醒當(dāng)前的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線程等待,而是當(dāng)前執(zhí)行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 ");
        // 死循環(huán),不斷運(yùn)行。
        while(true){;}  //  這個線程與主線程無關(guān),無 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();
            }
        }
    }
}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容