簡體   English   中英

在同步塊中使用wait()方法時,JVM是否在等待notify()時釋放監視器?

[英]When using wait() method in a synchronized block does JVM release the monitor while waiting for notify()?

我有一個線程啟動另一個線程,該線程執行的操作將導致事件在運行后觸發。 我需要在第一個線程中捕獲該事件(通過事件偵聽器),然后繼續其余的工作。 我的問題是,當第一個線程正在等待事件偵聽器調用notify()時,它將釋放監視器嗎? 如果沒有,我該如何設計該算法? 我是否正確地使用了wait()notify()方法並獲得了正確的鎖(線程1)?

代碼如下所示:

public class Thread1 {
    public void run() {
        Thread thread1 = Thread.currentThread();
        EventListener listener = new EventListener(thread1);
        Performer performer = new Performer();
        performer.addOnPerformedListener(listener);

        synchronized(thread1) {
            performer.run();    // Launches thread 2
            thread1.wait();
        }
        ...
    }

    public class EventListener implements Performer.OnPerformedListener {
        private Thread thread;

        public EventListener(Thread thread) {
            this.thread = thread;
        }

        @Override
        public void onPerformed() {
            synchronized (thread) {
                thread.notify();
            }
        }
    }
}

這很近。 但是,很難(在執行者中)知道沒有其余代碼有多接近。

首先,我建議不要在“ performer.run() ”調用上保持線程的鎖-如果可行的話。 盡可能使關鍵部分(保持鎖的代碼執行)盡可能小是“最佳實踐”。

其次,我建議使用在執行者中設置的條件標志(如果我正確理解了代碼),並在調用wait()之前在關鍵部分內執行檢查-以便錯過的通知不會導致錯過的條件。

這是偽代碼:

THREAD1
* Initialize THREAD2
* Start THREAD2
* synchronized ( THREAD2 ) { while ( THREAD2.conditionNotMet() ) { THREAD2.wait(); } }

THREAD2
* Initialize "condition not met"
* Run
* On condition met, set "condition met", then synchronized ( THREAD2 ) { THREAD2.notifyAll(); }

此外,如果該條件可能多次出現,並且等待該條件的代碼僅想在新出現的情況下繼續,請嘗試使用序列號,而不是僅“滿足條件”(例如, if ( myLastOccurrenceNumber < THREAD2.getLastOccurenceNumber ) { MET-CONDITION ) } else { WAIT } )。

您正在做什么的基本想法是正確的。 Object#wait()方法的Javadoc所述,它在Object#wait()時釋放您使用synchronized語句獲取的監視器:

當前線程必須擁有該對象的監視器。 線程釋放此監視器的所有權,並等待直到另一個線程通知等待在此對象的監視器上喚醒的線程

但是,有一個原因不能保證在您實施時在每種情況下都能正常工作,原因是wait調用也可以通過“中斷和虛假喚醒”來喚醒。 (它可以在您當前已實施的99%的情況下正常工作,這使其變得更加棘手,因為這會誤以為它會一直工作)

如Javadoc所述:

與一個參數版本中一樣,可能會產生中斷和虛假喚醒,並且應始終在循環中使用此方法:

 synchronized (obj) { while (<condition does not hold>) obj.wait(); ... // Perform action appropriate to condition } 

所以,你還需要什么來表示“執行”的情況做-the最簡單的方法是創建一個boolean名為場performed ,你設置為true調用之前notifyonPerformed方法。

thread1將正確看到此標志的值,因為thread2thread1獲取同一監視器之前釋放了監視器,並且這建立了Java內存模型規范中所述的事前發生關系。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM