2013-05-24 15 views
5

Ana yöntemle test ettiğimde 1'den 20'ye kadar sayılar için tablolar oluşturan basit bir örnek yazdım, tüm iş parçacıklarını çalıştırır (tüm iletileri yazdırır), Tüm iş parçacıkları çalıştırılmıyorken (tüm iletiler yazdırılmıyorken) JUnit sınaması ile aynı işlemi yaparken çoğu zaman (bazen tüm iş parçacıklarını çalıştırır). Bence çıktı açısından bir fark olmamalı. İşte JUnit sınaması, testte oluşturulan tüm iş parçacıklarını yürütmüyor

ana yöntemle sınıftır:
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"); 
     } 

    } 

} 

Ben tüm sonuçları yazdırır ana yöntemi çağırmak

. bazen bütün mesajları yazdırır yukarıdaki test durumda çalıştırıldığında

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

} 

, çıkış davranışı sahne consistant değildir:

Körük ana yönteme JUnit test eşdeğer kod ve çoğu zaman sadece birkaç tane basar ve çıkar. İşte yukarıdaki JUnit test durumda olması halinde yakalanan çıkışı:

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 

Çıktı/diğer parçacıkları kalan mesajlar baskı diğer konuları çalıştırmadan burada biter. Birisi bunun arkasındaki sebebi anlamama yardımcı olabilir. Şimdiden teşekkürler.

cevap

11

JUnit, test yönteminden erken çıkıyor. testCalculator() yönteminden çıkmadan önce tüm iş parçacıklarının tamamlanmasını beklemeniz gerekir.

Bunu yapmanın kolay bir yolu, CountDownLatch kullanmaktır.

  1. bir CountDownLatchCountDownLatch latch = new CountDownLatch(20) ile başlatın.

  2. Her bir Calculator kodunu, mandalla ilgili bir referansı çalıştırabilirsiniz. run() yönteminin sonunda, latch.countDown()'u arayın.

  3. testCalculator()'un sonunda latch.await() yöntemini çağırın. Bu, latch.countDown()'a 20 kez çağrılana kadar bloke edilecektir (diğer bir deyişle, tüm dişler tamamlandığında).

+0

Cevabınız için teşekkürler. Deneyeceğim. –

+0

Tamam. Anladım ama hala ana parçacığın neden başlaması/bitirmesi için başlattığı tüm ipleri beklediğini anlayamıyorum, aynı zamanda JUnit test ipliği buna izin vermiyor. Açıklayabilir misiniz lütfen. –

+0

Geri sayım mandalının nasıl çalıştığını mı soruyorsunuz? Yoksa neden tüm ipler tamamlanana kadar neden bloke etmeniz gerektiğini soruyor musunuz? –

4

Test metodunuz, tüm yumurtlayan dişler bitmeden tamamlanır. JUnit yürütücüsü tamamlandığında, tüm yumurtlayan dişler öldürülür.

Bu tür bir testi çalıştırmak istiyorsanız, oluşturduğunuz iş parçacıklarının bir koleksiyonunu ve test yönteminizin sonunda join() her birini tutmalısınız. Her iş parçacığı için join() çağrıları, ikinci bir döngüde yürütülür (tüm iş parçacıklarını başlatan döngüyü izleyerek).

+1

Bu, paralellikten faydalanmayacak, ancak bir kerede yalnızca bir iş parçacığı çalışır. Bunun yerine bir 'CountDownLatch' veya' ExecutorService # invokeAll (List ) 'yöntemini kullanarak bu yolla ilgili yöntemler vardır. –

+1

Tüm iş parçacığı var olan döngüde başlatılan start() 'dır. Cevap, test yönteminin sonunda, her bir oluşturulmuş iş parçacığına 'join()' diyen ikinci bir döngü eklemektir. 'Join()' çağrısı, iş parçacığı bitinceye kadar geri dönmez.Paralellikten tam olarak yararlanır ve tüm yumruların işlenmesinden önce yapılmasını sağlar. CountDownLatch, her iş parçacığının istisnaları olsa bile geri sayımını sağlamak için dikkatli bir kodlama gerektirir. ExecutorService hala Callable (veya Runnable) yapılıncaya kadar beklemenizi gerektirir. – Rob

+0

Ahh, tamam. 'Join() 'seçeneğini kullanmayı kabul ediyorum. Cevabınızdaki "yöntemin sonunda ikinci döngü" açıklığa kavuşturmak isteyebilirsiniz. Bir 'CountDownLatch' kullanarak, OP için iyi çalışırdı (' Calculator' runnable'da istisnalar atılmaz). yerine olursa olsun üzerinde yürütme ne bilgisayar 20 konuları oluşturmak yerine, kullanan bir iş parçacığı havuzu 'Runtime.getRuntime() yaratabilir çünkü' ExecutorService' burada bile en iyi seçenek olabilir. Bunun yerine availableProcessors() 'iplikler. Sonra 'invokeAll()' ifadesini çağırmak, tüm callables'leri yürütecek ve hepsi tamamlanana kadar engellenecektir. –