簡體   English   中英

如何在Java中沒有等待信號后等待調用的條件?

[英]How to await a Condition without the chance of await being called after signal in Java?

我的代碼中有一個等待/通知機制,基本上像這樣包裝了LockCondition

class ConditionWithTimeout { // timeout part omitted
    private Lock lock = new ReentrantLock();
    private Condition cond = lock.newCondition();

    public void doWait() throws InterruptedException {
        lock.lock();
        cond.await();
        lock.unlock();
    }

    public void doNotify() {
        lock.lock();
        cond.signalAll();
        lock.unlock();
    }
}

我的問題是,如果我做這樣的事情:

someFunction();
myCond.doWait();

如果someFunctiondoNotify上的某個時刻調用doNotifymyCondition我可能會等到myCondition超時,因為doWait中的someFunction可能會在此代碼跳至下一行執行myCond.doWait之前執行。

我通過添加preWaitFn解決了preWaitFn

class ConditionWithTimeout {
    private Lock lock = new ReentrantLock();
    private Condition cond = lock.newCondition();
    private Executor hookExecutor = Executors.newSingleThreadExecutor();

    public void doWait() throws InterruptedException {
        doWait(() -> {
        });
    }

    public void doWait(Runnable preWaitFn) throws InterruptedException {
        lock.lock();
        hookExecutor.execute(preWaitFn);
        cond.await();
        lock.unlock();
    }

    public void doNotify() {
        lock.lock();
        cond.signalAll();
        lock.unlock();
    }
}

和它的作品,但現在這似乎是一個代碼味道對我來說,因為它仍然是可能的doNotify之前被稱為cond.await被調用。

所以我的問題是,在這種情況下最佳做法是什么? 我需要阻塞,直到someFunction完成其工作,但我希望避免出現這種someFunction情況。

通常的模式是檢查某些邏輯條件,並將該信號用作通知另一線程該條件已更新的手段。 就您而言,一個簡單的標志就足夠了:

private boolean flag = false;

public void doWait() throws InterruptedException {
    lock.lock();
    try {
        // Loop is necessary to avoid spurious wakeup
        while (!flag) {
            cond.await();
        }
    } finally {
        // Unlock in finally in case exception is thrown
        lock.unlock();
    }
}

public void doNotify() {
    lock.lock();
    try {
        flag = true;
        cond.signalAll();
    } finally {
        lock.unlock();
    }
}

您可以嘗試使用CountDownLatch 根據您的用例,這可能不是最佳答案-如果您可以為每個調用創建一個flag對象的新實例,但如果您需要重用一個實例,則可以用。 鏈接的Javadoc頁面包含有關如何使用它的示例。 這基本上是shmosel答案的現成替代品。

暫無
暫無

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

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