2017-01-10 3 views
0

私は基本的にこのようなLockConditionをラップ私のコードで待機/通知メカニズムがあります。Javaで信号の後に待たれる可能性のない状態を待つ方法は?

someFunction(); 
myCond.doWait(); 

それがいる可能性がある:私の問題は、私はこのような何かを行う場合ということです

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

someFunctiondoNotifyを呼び出した場合myConditionmyConditionがタイムアウトするまでsomeFunctiondoWaitが実行される可能性があります。このコードがexecの次の行にジャンプする前に実行される可能性があります。 ute myCond.doWait

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

をし、それが動作するようになりましたが、cond.awaitが呼び出される前にdoNotifyが呼び出されることは可能ですので、これは私にはコードのにおいのように思えます。

私の質問は、そのような状況ではどのようなベストプラクティスですか? someFunctionの作業が終了するまでブロックする必要がありますが、このようなコーナーケースは避けたいと思います。

答えて

1

一般的なパターンは、いくつかの論理条件をチェックし、その条件が更新されたことを別のスレッドに通知する手段として信号を使用することです。あなたのケースでは、単純なフラグで十分です:

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

あなたはCountDownLatchを使用して試みることができます。ユースケースによっては、これは最善の答えではないかもしれません。フラグオブジェクトを再利用する必要がある場合ではなく、呼び出しごとにフラグオブジェクトの新しいインスタンスを作成できる場合に機能します。リンクされたJavadocページには、その使用方法の例が含まれています。これは、基本的にshmoselの答えに対する既製品の交換品です。

+0

私のケースでは 'CountDownLatch'が働いています(私の質問で詳しく述べられていない理由で)が、私は心に留めておきます! –

関連する問題