2012-05-26 34 views
5

別のコンポーネント(別のスレッドで実行中)から特定のイベントを待つためにCountDownLatchを使用します。次のアプローチは、私のソフトウェアの意味に合うだろうが、私は私が期待通りに動作するかどうかわからない:タイムアウトでCountDownLatch.await(int)を複数呼び出す

mCountDownLatch.await(3000, TimeUnit.MILLISECONDS) 
otherComponent.aStaticVolatileVariable = true; 
mCountDownLatch.await(3500, TimeUnit.MILLISECONDS); 
... <proceed with other stuff> 

シナリオでは、次のようになります。私は、3秒間待ち、ラッチがある場合0にカウントダウンされていない場合は、その変数で他のコンポーネントに通知してから、最大3.5秒待機します。もう一度タイムアウトがあれば、私は気にせず、他の操作を進めます。

注:私はそれがそうではないことを知っていますが、上記のシナリオは私のソフトウェアで全く合理的かつ有効です。

私はawait(int、TimeUnit)とCountDownLatchのドキュメントを読んだが、私はJava/Androidの専門家ではないので、確認が必要です。私には、すべてのシナリオが有効になります:

  • 最初のawaitが成功した場合、もう一方が出て最初のawait時間は、その後、他のawaitがまだ有効である場合
  • すぐに戻ります待ちます。 他のスレッドが静的な信号に気付いた場合、したがって、第二 のawaitが正常に
  • の両方が通話時間を待つ返すことがあります(これは私のソフトウェアのセマンティクスに応じて結構です)

私は(のawaitを使用しています。.. 。)正しく?同じオブジェクトの前の待っている(...)がタイムアウトしても、上記の方法で(...)秒待つことができますか?

答えて

4

私があなたの質問を正しく理解していれば、このテストはあなたの前提条件/要件がすべて満たされていることを証明します。 (JUnitのとHamcrestを実行します。)runCodeUnderTest()方法でコードを注意してください、それは時間の記録が点在していますし、タイムアウトが非常に徹底したコードのための10

import org.junit.Before; 
import org.junit.Test; 

import java.util.concurrent.CountDownLatch; 
import java.util.concurrent.TimeUnit; 

import static org.hamcrest.Matchers.closeTo; 
import static org.hamcrest.Matchers.lessThan; 
import static org.junit.Assert.assertThat; 

public class CountdownLatchTest { 
    static volatile boolean signal; 
    CountDownLatch latch = new CountDownLatch(1); 
    long elapsedTime; 
    long[] wakeupTimes = new long[2]; 

    @Before 
    public void setUp() throws Exception { 
     signal = false; 
    } 

    @Test 
    public void successfulCountDownDuringFirstAwait() throws Exception { 
     countDownAfter(150); 
     runCodeUnderTest(); 
     assertThat((double) elapsedTime, closeTo(150, 10)); 
     assertThat(wakeupTimeSeparation(), lessThan(10)); 
    } 

    @Test 
    public void successfulCountDownDuringSecondAwait() throws Exception { 
     countDownAfter(450); 
     runCodeUnderTest(); 
     assertThat((double) elapsedTime, closeTo(450, 10)); 
     assertThat((double) wakeupTimeSeparation(), closeTo(150, 10)); 
    } 

    @Test 
    public void neverCountDown() throws Exception { 
     runCodeUnderTest(); 
     assertThat((double) elapsedTime, closeTo(650, 10)); 
     assertThat((double) wakeupTimeSeparation(), closeTo(350, 10)); 
    } 

    @Test 
    public void countDownAfterSecondTimeout() throws Exception { 
     countDownAfter(1000); 
     runCodeUnderTest(); 
     assertThat((double) elapsedTime, closeTo(650, 10)); 
     assertThat((double) wakeupTimeSeparation(), closeTo(350, 10)); 
    } 

    @Test 
    public void successfulCountDownFromSignalField() throws Exception { 
     countDownAfterSignal(); 
     runCodeUnderTest(); 
     assertThat((double) elapsedTime, closeTo(300, 10)); 
    } 

    private int wakeupTimeSeparation() { 
     return (int) (wakeupTimes[1] - wakeupTimes[0]); 
    } 

    private void runCodeUnderTest() throws InterruptedException { 
     long start = System.currentTimeMillis(); 
     latch.await(300, TimeUnit.MILLISECONDS); 
     wakeupTimes[0] = System.currentTimeMillis(); 
     signal = true; 
     latch.await(350, TimeUnit.MILLISECONDS); 
     wakeupTimes[1] = System.currentTimeMillis(); 
     elapsedTime = wakeupTimes[1] - start; 
    } 

    private void countDownAfter(final long millis) throws InterruptedException { 
     new Thread(new Runnable() { 
      @Override 
      public void run() { 
       sleep(millis); 
       latch.countDown(); 
      } 
     }).start(); 
    } 

    private void countDownAfterSignal() { 
     new Thread(new Runnable() { 
      @Override 
      public void run() { 
       boolean trying = true; 
       while (trying) { 
        if (signal) { 
         latch.countDown(); 
         trying = false; 
        } 
        sleep(5); 
       } 
      } 
     }).start(); 
    } 

    private void sleep(long millis) { 
     try { 
      Thread.sleep(millis); 
     } catch (InterruptedException e) { 
      throw new IllegalStateException("Unexpected interrupt", e); 
     } 
    } 
} 
+0

感謝の要因によって減少しているが。実際、私の質問はこれよりはるかに簡単でしたが、私が正しいとすれば、実際には私の前提が正しいことが証明されました。私の中心的な質問はこれだけでした:オブジェクトが最初に待たされたとき(**)、同じオブジェクトに対してもう一度await()を呼び出せますか?私はそう思うが、私が言ったように、私はJavaの専門家ではない。 (私が最後の確認を得た後、私は必要以上のものであるため、あなたの返答を確かに答えにします。) –

+1

正直言って、私は100%私の頭、そしてそのような答えを見つける最善の方法は、それを試すことです。したがって、テスト:) –

関連する問題