2012-07-25 80 views

回答

5

而不是編寫自己的方法來啓動線程,爲什麼不使用Executor,它可以注入你的課堂?然後,您可以通過傳入虛擬Executor來輕鬆測試它。

編輯:這裏是你的代碼是如何可以構造一個簡單的例子:

public class ResultCalculator { 
    private final ExecutorService pool; 
    private final List<Future<Integer>> pendingResults; 

    public ResultCalculator(ExecutorService pool) { 
     this.pool = pool; 
     this.pendingResults = new ArrayList<Future<Integer>>(); 
    } 

    public void startComputation() { 
     for (int i = 0; i < 5; i++) { 
      Future<Integer> future = pool.submit(new Robot(i)); 
      pendingResults.add(future); 
     } 
    } 

    public int getFinalResult() throws ExecutionException { 
     int total = 0; 
     for (Future<Integer> robotResult : pendingResults) { 
      total += robotResult.get(); 
     } 
     return total; 
    } 
} 

public class Robot implements Callable<Integer> { 
    private final int input; 

    public Robot(int input) { 
     this.input = input; 
    } 

    @Override 
    public Integer call() { 
     // Some very long calculation 
     Thread.sleep(10000); 

     return input * input; 
    } 
} 

下面是你如何把它從你的main()

public static void main(String args) throws Exception { 
    // Note that the number of threads is now specified here 
    ExecutorService pool = Executors.newFixedThreadPool(5); 
    ResultCalculator calc = new ResultCalculator(pool); 
    try { 
     calc.startComputation(); 
     // Maybe do something while we're waiting 
     System.out.printf("Result is: %d\n", calc.getFinalResult()); 
    } finally { 
     pool.shutdownNow(); 
    } 
} 

這裏是你如何'd測試它(假設JUnit 4和Mockito):

@Test 
@SuppressWarnings("unchecked") 
public void testStartComputationAddsRobotsToQueue() { 
    ExecutorService pool = mock(ExecutorService.class); 
    Future<Integer> future = mock(Future.class); 
    when(pool.submit(any(Callable.class)).thenReturn(future); 

    ResultCalculator calc = new ResultCalculator(pool); 
    calc.startComputation(); 

    verify(pool, times(5)).submit(any(Callable.class)); 
} 

請注意,所有這些代碼只是一個草圖,我還沒有測試甚至試圖編譯。但它應該讓你瞭解代碼的結構。

+0

請參閱我對@Alex D的迴應。你能舉個例子嗎? – kasavbere 2012-07-25 06:40:04

+0

@kasavbere請參閱提供幾個示例的[ExecutorService的javadoc](http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ExecutorService.html)。 – assylias 2012-07-25 09:14:37

+0

感謝這個例子。 – kasavbere 2012-07-30 00:51:49

4

而不是說你要「測試五個線程已經開始」,最好退一步考慮五線程實際上應該是什麼。然後進行測試以確保「某事」實際上正在完成。

如果你真的只想測試線程已經啓動,那麼你可以做一些事情。你是否保持對某個地方的線程的引用?如果是這樣,您可以檢索參考文獻,對它們進行計數,並在每個參考文獻上撥打isAlive()(檢查它是否返回true)。

我相信在某些Java平臺類中有一些方法,您可以調用它來查找有多少個線程正在運行,或查找所有在ThreadGroup中運行的線程,但是您必須搜索以找出它是。

更多的想法響應您的評論

如果你的代碼是new Thread(runnable).start()一樣簡單,我不會刻意去測試該線程實際上是開始。如果你這樣做,你基本上只是測試Java平臺的工作原理(它的確如此)。如果你初始化和啓動線程的代碼比較複雜,我會把thread.start()部分取出來,並確保這個存根被稱爲所需的次數,並帶有正確的參數等。

無論你做什麼關於這一點,我會絕對測試在多線程模式下運行時任務是否正確完成。從個人經驗,我可以告訴你儘快當你開始做什麼遠程複雜的線程,它很容易得到微妙的錯誤,只有在某些條件下,也許只是偶爾出現。處理多線程代碼的複雜性是一個非常滑的斜坡。因此,如果你能做到這一點,我會高度建議你不僅僅是簡單的單元測試。在多核線程上,多核機器上,非常大的數據集上執行壓力測試,並確保所有答案都與預期完全一致。

此外,雖然您期待使用線程的性能提升,但我建議您使用不同數量的線程來測試您的程序,以確保達到預期的性能提升。根據您的系統設計方式,可能會發現併發瓶頸,這可能會使您的程序在線程中的速度難於沒有線程。在某些情況下,它甚至可以是較慢的

+0

五個線程用於加速一個線程可以執行的進程。想象一下,讓五個遠程機器人做些事情然後回報。我的測試環境使用虛擬數據,因此'isAlive'不能保證能正常工作。此外,檢查結果並不會顯示任何內容,因爲[生產環境]中唯一明顯的變化就是速度。 – kasavbere 2012-07-25 06:35:26

+0

感謝您的幫助。投票。 – kasavbere 2012-07-30 00:52:14