2013-05-17 15 views
13

Tôi đang cố gắng viết một bài kiểm tra đơn vị yêu cầu các chuỗi mulitple. Tuy nhiên, có vẻ như các chủ đề chỉ dừng một phần thông qua thực hiện. Hãy xem xét mã sau:Chủ đề hoạt động lạ lùng trong JUnit

public class Test { 
    @org.junit.Test 
    public void TestThreads() { 
     new Thread(new Runnable() { 
      public void run() { 
       for (int i = 1; i < 1000; i++) System.out.println(i); 
      } 
     }).start(); 
    } 
} 

Nếu tôi chạy thử nghiệm đơn vị này, nói chung sẽ dừng hiển thị đầu ra ở đâu đó giữa 140-180. Nếu tôi chuyển đổi mã này thành một lớp thông thường và chạy nó, nó hoạt động tốt. Có ai có bất kỳ ý tưởng những gì tôi đang thiếu ở đây?

Cảm ơn, - Andrew.

Trả lời

0

Có thể là chuỗi chủ đề đang chạy thử nghiệm đang kết thúc. Nếu bạn có thể tránh nó thì đừng tạo ra một chủ đề mới trong các bài kiểm tra của bạn. Tôi sẽ tạo một lớp mới thực hiện runnable và sau đó kiểm tra lớp mà tôi gọi đơn giản là chạy trên đối tượng đó. Bạn không cần phải kiểm tra lập lịch trình chuỗi như một phần của bài kiểm tra của mình. Hy vọng rằng nhóm nhà phát triển ngôn ngữ java đã được bảo vệ :)

6

Trong chức năng TestThread, JUnit không có cách nào nói rằng bạn đã sinh ra một chuỗi mới. Nó reclaims bất kỳ đối tượng nó tạo ra trong chức năng ngay sau khi chức năng kết thúc (dòng cuối cùng là đạt) và không biết về các chủ đề.

Vì lý do này, bạn thấy Đầu ra từ Chủ đề cho đến khi nó bị giết. Nếu bạn muốn đợi cho Hoàn thành Chủ đề, bạn có thể sử dụng Thread.join (ngay sau khi bạn gọi Thread.start()) để làm cho nó chờ kết quả hoặc sử dụng wait-notify trên một số đối tượng.

Ngoài ra, tìm thấy câu hỏi này: JUnit terminates child threads

+0

Để nói rằng các đối tượng xóa 'JUnit' có một chút gây hiểu lầm, vì trong Java, không có cách nào để xóa một đối tượng một cách rõ ràng. –

+0

@Martin đúng. nhưng JVM có thể lấy lại (GC) khi đối tượng không cần nữa. Một khi các bài kiểm tra được thực hiện, JUnit giết Chủ đề và về cơ bản toàn bộ JVM. – goblinjuice

+0

@goblinjuice không có nghĩa là JUnit giết chết một thể hiện đối tượng nào cả. Kể từ khi JVM thoát, mỗi bit bộ nhớ được sử dụng sẽ được giải phóng. –

22

Bạn có thể sử dụng Thread.join() để ngăn chặn sự kiểm tra từ khi kết thúc trước khi thread mới đã hoàn thành nhiệm vụ của mình:

@org.junit.Test 
public void TestThreads() throws InterruptedException { 
    Thread t = new Thread(new Runnable() { 
     public void run() { 
      for (int i = 1; i < 1000; i++) System.out.println(i); 
     } 
    }); 
    t.start(); 
    t.join(); 
} 

Thông thường, các JVM sẽ chấm dứt khi cuối cùng chủ đề không daemon chấm dứt. Bạn có thể mong đợi rằng chỉ cần gọi t.setDaemon(false) trên luồng sẽ ngăn không cho JVM thoát khỏi trước khi tác vụ kết thúc. Tuy nhiên, junit sẽ call System.exit() khi chuỗi chính đã kết thúc.

Khi Gus ghi chú trong nhận xét: "bạn cần tham gia() vì start() không chặn".

Đúng là bạn cũng có thể gọi run() trong ví dụ tối thiểu này. Tuy nhiên, tôi cho rằng bạn đang bắt đầu một chuỗi vì bạn muốn nó chạy đồng thời với một luồng khác. Gọi run() trên một Chủ đề được gắn cờ là một lỗi có thể xảy ra bởi FindBugs - nếu bạn chỉ cần gọi run(), bạn có thể chỉ muốn triển khai Runnable thay vì sử dụng Thread.

+0

Sigh - đánh tôi với cú đấm công bằng và vuông. –

+1

Điều đáng nói đến trong giải pháp của bạn là bạn cần Join() vì Start() không chặn. IIRC, Bạn cũng có thể chỉ cần sử dụng Run() nếu bạn sẽ không làm bất cứ điều gì simulataneously. – Gus

+0

@Gus sử dụng 'run' trên một cá thể' Thread' là một ý tưởng tồi. Tại sao?Bởi vì sử dụng 'run' không làm cho nó thành một chuỗi, chỉ là một đối tượng đơn giản. –