2013-05-24 32 views
5

Tôi đã viết một ví dụ đơn giản cho việc tạo luồng cho các số bắt đầu từ 1 đến 20. khi tôi thử nghiệm nó với phương thức chính nó thực thi tất cả các luồng (in tất cả các thông điệp), trong khi tất cả các chủ đề không được chạy (tất cả các thư không được in) hầu hết các lần (đôi khi nó chạy tất cả các chủ đề) khi làm tương tự với kiểm tra JUnit. Tôi nghĩ rằng không nên có bất kỳ sự khác biệt về đầu ra.Thử nghiệm JUnit không thực hiện tất cả các chủ đề được tạo ra trong bài kiểm tra

Đây là lớp học với phương pháp chính:

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

    } 

} 

Khi tôi gọi phương pháp chính nó in tất cả các kết quả.

Bellow là mã cho thử nghiệm JUnit tương đương với phương pháp chính:

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

} 

Khi tôi chạy test trên, hành vi của các đầu ra không nhất quán trong cảnh mà đôi khi nó in tất cả các tin nhắn và hầu hết thời gian chỉ in một vài lần và thoát. Đây là kết quả đầu ra được chụp trong trường hợp của trường hợp kiểm tra JUnit ở trên:

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 

Đầu ra kết thúc tại đây mà không in các thông điệp còn lại trong các chủ đề khác/thực hiện các chủ đề khác.

Ai đó có thể giúp tôi hiểu lý do đằng sau điều này. Cảm ơn trước.

Trả lời

11

JUnit sẽ sớm thoát khỏi phương pháp thử nghiệm. Bạn cần đợi tất cả các chuỗi hoàn tất trước khi thoát phương thức testCalculator().

Cách dễ dàng để thực hiện điều đó là sử dụng CountDownLatch.

  1. Khởi tạo số CountDownLatch với CountDownLatch latch = new CountDownLatch(20).

  2. Vượt qua từng Calculator có thể chạy một tham chiếu đến chốt. Ở cuối phương thức run(), hãy gọi latch.countDown().

  3. Vào cuối cuộc gọi phương thức testCalculator()latch.await(). Điều này sẽ chặn cho đến khi latch.countDown() được gọi là 20 lần (nghĩa là khi tất cả các chuỗi đã hoàn thành).

+0

Cảm ơn bạn đã trả lời. Tôi sẽ thử nó. –

+0

OK. Tôi nhận được quan điểm của bạn nhưng tôi vẫn không thể hiểu tại sao thread chính chờ đợi cho tất cả các chủ đề bắt đầu bởi nó để hoàn thành/kết thúc, trong khi đồng thời các chủ đề kiểm tra JUnit không cho phép điều này. Bạn có thể vui lòng giải thích nó. –

+0

Bạn có hỏi làm thế nào đếm ngược chốt hoạt động? Hoặc là bạn hỏi tại sao bạn cần phải chặn cho đến khi tất cả các chủ đề đã hoàn thành? –

4

Phương pháp thử nghiệm của bạn kết thúc trước khi tất cả các chủ đề sinh ra được hoàn thành. Khi thực thi JUnit kết thúc, tất cả các luồng sinh ra đều bị giết.

Nếu bạn muốn chạy loại thử nghiệm này, bạn nên giữ một tập hợp các chủ đề bạn đã tạo và join() mỗi chủ đề ở cuối phương pháp thử nghiệm của bạn. Các cuộc gọi đến join() mỗi luồng được thực hiện trong một vòng lặp thứ hai (sau vòng lặp bắt đầu tất cả các chuỗi).

+1

Điều này sẽ không tận dụng lợi thế của song song ... chỉ có một chuỗi sẽ chạy cùng một lúc. Có nhiều cách xung quanh việc này bằng cách sử dụng phương thức 'CountDownLatch' hoặc phương thức' ExecutorService # invokeAll (List ) '. –

+1

Tất cả các luồng có 'start()' được gọi trong vòng lặp hiện có. Câu trả lời là thêm một vòng lặp thứ hai ở phần cuối của phương thức thử nghiệm gọi là 'join()' trên mỗi luồng sinh ra. Lệnh 'join()' không trả về cho đến khi luồng đó kết thúc.Tận dụng triệt để tính song song và đảm bảo rằng tất cả các luồng sinh sản được thực hiện trước khi trở về. CountDownLatch yêu cầu mã hóa cẩn thận để đảm bảo rằng tất cả các chuỗi đếm ngược ngay cả khi nó có ngoại lệ. ExecutorService vẫn yêu cầu bạn đợi cho đến khi có thể gọi (hoặc Runnable) được thực hiện. – Rob

+0

Ahh, OK. Tôi đồng ý về việc sử dụng 'join()' sau đó. Bạn có thể muốn làm rõ "vòng lặp thứ hai ở cuối phương thức" trong câu trả lời của bạn. Sử dụng một 'CountDownLatch' sẽ làm việc tốt cho OP mặc dù (không có ngoại lệ được ném trong' Calculator' runnable). Và 'ExecutorService' thậm chí có thể là tùy chọn tốt nhất ở đây vì thay vì tạo 20 luồng cho dù bạn đang thực thi máy tính nào, bạn có thể tạo một nhóm luồng bằng cách sử dụng' Runtime.getRuntime(). AvailableProcessors() 'threads. Sau đó, gọi 'invokeAll()' sẽ thực hiện tất cả các cuộc gọi và sẽ chặn cho đến khi chúng hoàn tất. –

Các vấn đề liên quan