2013-05-24 24 views
5

1から20までの番号のテーブルを生成するスレッドの簡単な例を書いたのですが、mainメソッドでテストしたときに、 JUnitテストでは、すべてのスレッドは実行されません(すべてのメッセージは印刷されません)。ほとんどの場合、すべてのスレッドが実行されます。私は出力の点で違いがあってはならないと思います。ここでJUnitテストでは、テスト内で作成されたすべてのスレッドが実行されていません

は、mainメソッドを持つクラスです:

public class Calculator implements Runnable { 

    private int number; 

    Calculator(final int number){ 
     this.number = number; 
    } 

    @Override 
    public void run() { 
     for(int i = 1; i <= 10; i++){ 
      System.out.printf("%s : %d * %d = %d \n", Thread.currentThread().getName(), number, i, number * i); 
     } 

    } 

    public static void main(String[] args){ 
     Calculator calculator = null; 
     Thread thread = null; 
     for(int i = 1; i < 21; i ++){ 
      calculator = new Calculator(i); 
      thread = new Thread(calculator); 
      System.out.println(thread.getName() + " Created"); 
      thread.start(); 
      System.out.println(thread.getName() + " Started"); 
     } 

    } 

} 

私はそれがすべての結果を出力するmainメソッドを呼び出すと。

ベローがメインメソッドにJUnitテスト同等のコードである:

public class CalculatorTest { 

private Calculator calculator; 
private Thread thread; 

@Test 
public void testCalculator() { 
    for(int i = 1; i < 21; i ++){ 
     calculator = new Calculator(i); 
     thread = new Thread(calculator); 
     System.out.println(thread.getName() + " Created"); 
     thread.start(); 
     System.out.println(thread.getName() + " Started"); 
    } 
} 

} 

Iは、上記のテストケースを実行すると、出力の挙動は、時にはそれがすべてのメッセージを印刷することをシーンに一貫性はありませんほとんどの場合、印刷されるのはほんのわずかで、出口です。ここで上記JUnitテストケースの場合に取り込まれ出力される。

Thread-0 Created 
Thread-0 Started 
Thread-1 Created 
Thread-1 Started 
Thread-2 Created 
Thread-2 Started 
Thread-3 Created 
Thread-3 Started 
Thread-4 Created 
Thread-4 Started 
Thread-5 Created 
Thread-5 Started 
Thread-6 Created 
Thread-6 Started 
Thread-7 Created 
Thread-7 Started 
Thread-8 Created 
Thread-8 Started 
Thread-9 Created 
Thread-9 Started 
Thread-10 Created 
Thread-10 Started 
Thread-11 Created 
Thread-11 Started 
Thread-12 Created 
Thread-12 Started 
Thread-13 Created 
Thread-13 Started 
Thread-14 Created 
Thread-14 Started 
Thread-15 Created 
Thread-15 Started 
Thread-16 Created 
Thread-16 Started 
Thread-17 Created 
Thread-17 Started 
Thread-18 Created 
Thread-18 Started 
Thread-19 Created 
Thread-19 Started 
Thread-0 : 1 * 1 = 1 
Thread-0 : 1 * 2 = 2 
Thread-0 : 1 * 3 = 3 
Thread-0 : 1 * 4 = 4 
Thread-0 : 1 * 5 = 5 
Thread-0 : 1 * 6 = 6 
Thread-0 : 1 * 7 = 7 
Thread-0 : 1 * 8 = 8 
Thread-0 : 1 * 9 = 9 
Thread-0 : 1 * 10 = 10 
Thread-2 : 3 * 1 = 3 
Thread-2 : 3 * 2 = 6 
Thread-2 : 3 * 3 = 9 
Thread-2 : 3 * 4 = 12 
Thread-2 : 3 * 5 = 15 
Thread-2 : 3 * 6 = 18 
Thread-2 : 3 * 7 = 21 

出力/他のスレッド内に残っているメッセージを印刷する他のスレッドを実行せずに終了します。

誰かがこの背後にある理由を理解するのを助けることができますか?前もって感謝します。

答えて

11

JUnitはテストメソッドを早期に終了しています。 testCalculator()メソッドを終了する前に、すべてのスレッドが完了するのを待つ必要があります。

簡単な方法は、CountDownLatchを使用することです。

  1. CountDownLatch latch = new CountDownLatch(20)CountDownLatchを初期化します。

  2. Calculator実行可能にラッチへの参照を渡します。 run()メソッドの最後にはlatch.countDown()と呼び出します。

  3. testCalculator()の最後に、メソッド呼び出しlatch.await()があります。これは、latch.countDown()が20回呼び出されるまで(つまり、すべてのスレッドが完了したとき)ブロックされます。

+0

返信ありがとうございます。やってみます。 –

+0

OK。私はあなたの意見を持っていますが、それでも主スレッドが完了/完了するために開始したすべてのスレッドを待つ理由を理解できません。同時に、JUnitテストスレッドはこれを許可していません。あなたはそれを説明してもらえますか? –

+0

カウントダウンラッチがどのように機能するのか尋ねていますか?それとも、すべてのスレッドが完了するまでブロックする必要があるのですか? –

4

スポーンされたスレッドがすべて終了する前に、テストメソッドが終了します。 JUnitエグゼキュータが終了すると、生成されたすべてのスレッドが強制終了されます。

この種のテストを実行する場合は、作成したスレッドのコレクションを、テストメソッドの最後にそれぞれjoin()としておく必要があります。 join()への呼び出しは、2番目のループ(すべてのスレッドを開始するループに続く)で実行されます。

+1

これは並列性を利用しませんが...ただ1つのスレッドだけが一度に実行されます。代わりに 'CountDownLatch'や' ExecutorService#invokeAll(List ) 'メソッドを使うことで、これを回避する方法があります。 –

+1

すべてのスレッドは、既存のループで 'start()'を呼び出します。答えは、テストメソッドの最後に、各生成されたスレッドで 'join()'を呼び出す2番目のループを追加することです。 'join()'呼び出しは、そのスレッドが終了するまで戻りません。並列性をフルに活用し、生成されたすべてのスレッドが戻る前に確実に実行されるようにします。 CountDownLatchは、例外があってもすべてのスレッドがカウントダウンするように慎重にコーディングする必要があります。 ExecutorServiceでは、Callable(またはRunnable)が完了するまで待つ必要があります。 – Rob

+0

ああ、OK。私は 'join()'の使用に同意します。あなたの答えでは、 "メソッドの最後に2番目のループ"を明確にしたいかもしれません。 'CountDownLatch'を使うと、OPのためにうまくいくでしょう(例外は' Calculator'ランナブルでスローされません)。また、実行中のコンピュータに関係なく20個のスレッドを作成するのではなく、 'Runtime.getRuntime()。availableProcessors()'スレッドを使用してスレッドプールを作成できるので、 'ExecutorService'が最適なオプションです。 'invokeAll()'を呼び出すと、すべての呼び出し可能ファイルが実行され、すべて完了するまでブロックされます。 –

関連する問題