5

ブックJava Concurrency in Practice at Listing 12.3 によると、次のサンプル コードを使用して並行コードをテストできます。

void testTakeBlocksWhenEmpty() {
 final BoundedBuffer<Integer> bb = new BoundedBuffer<Integer>(10);
 Thread taker = new Thread() {
  public void run() {
   try {
    int unused = bb.take();
    fail(); // if we get here, it’s an error
   } catch (InterruptedException success) { }
  }
 };
 try {
  taker.start();
  Thread.sleep(LOCKUP_DETECT_TIMEOUT);
  taker.interrupt();
  taker.join(LOCKUP_DETECT_TIMEOUT);
  assertFalse(taker.isAlive());
 } catch (Exception unexpected) {
  fail();
 }
}

次の手順が実行されるとします。

  1. takerスレッドが開始されました。
  2. bb.take()fail()正常に返され、メソッド実行まであと少しです。
  3. メソッドといいinterrupt()ます。
  4. 私たちはスレッドのcatchブロックにいます。taker

そのため、現時点では catch ブロックにいますが、実際にはテスト メソッドは失敗しています。それは失敗し、通知されることはありません。

これは正しいですか?はいの場合、どうすればこれを修正できますか?

4

2 に答える 2

0

take空のキューでブロックすることになっています。したがって、イベントの予想されるシーケンスは次のとおりです。

  • taker.start();=>スレッドを開始
  • Thread.sleep(LOCKUP_DETECT_TIMEOUT);スレッドが開始takeされ、呼び出されたことを確認するまで待ちます。定数の実際の値を推定するのは困難ですが、数百ミリを超える値であれば十分です。代わりに、CountDownLatch を使用して、テイカー スレッドがいつ開始されたかを知ることができます。
  • テイカー スレッド内: bb.take();=> はブロックされるはずです -fail()呼び出されない場合、テストは失敗します
  • メインスレッドで:taker.interrupt();=>take()メソッドは終了するはずですInterruptedException
  • メインスレッドで:taker.join();=>テイカースレッドが終了するまでしばらく待ちます
  • メインスレッドで:assertFalse(taker.isAlive());=>テイカースレッドが終了し、takeメソッドでブロックされていないことを確認します

ラッチ付きのバージョン (が呼び出される前に スレッドが中断された場合、InterruptedException で終了することを前提としています。そうでない場合は、呼び出す前にランダムなスリープを追加する以外に方法はありません):taketakestarted.await()

void testTakeBlocksWhenEmpty() {
 final CountDownLatch started = new CountDownLatch(1);
 final CountDownLatch ended = new CountDownLatch(1);
 final BoundedBuffer<Integer> bb = new BoundedBuffer<Integer>(10);
 Thread taker = new Thread() {
  public void run() {
   try {
    started.countDown();
    int unused = bb.take();
    fail(); // if we get here, it’s an error
   } catch (InterruptedException success) { }
   ended.countDown();
  }
 };
 try {
  taker.start();
  started.await();
  taker.interrupt();
  assertTrue(ended.await());
 } catch (Exception unexpected) {
  fail();
 }
}

テスト メソッドまたはラッチにタイムアウトを追加する必要があります (テストが成功した場合に干渉しないように十分な長さ、たとえば 5 秒)。これにより、テスト スイート全体がブロックされるのを回避できます。

于 2013-10-02T08:43:07.217 に答える