我写了一个简单的线程示例,它为从1到20开始的数字生成表。当我用main方法测试它时,它执行所有线程(打印所有消息),而所有线程都没有运行(所有消息)在使用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方法时,它会打印所有结果。
Bellow是JUnit测试的代码,相当于main方法:
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");
}
}
}
当我运行上面的测试用例时,输出的行为在场景中是不一致的,有时它会打印所有消息,并且大多数时候只打印少量并退出。以下是在上述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
此处的输出结束,而不打印其他线程中的剩余消息/执行其他线程。
有人可以帮助我理解这背后的原因。提前谢谢。
答案 0 :(得分:12)
JUnit提前退出测试方法。在退出testCalculator()
方法之前,您需要等待所有线程完成。
一种简单的方法是使用CountDownLatch
。
使用CountDownLatch
初始化CountDownLatch latch = new CountDownLatch(20)
。
将每个Calculator
可运行的引用传递给锁存器。在run()
方法结束时,请致电latch.countDown()
。
testCalculator()
方法调用latch.await()
的末尾。这将阻止latch.countDown()
被调用20次(即所有线程都已完成)。
答案 1 :(得分:5)
您的测试方法在所有生成的线程完成之前完成。当JUnit执行程序完成时,所有生成的线程都将被终止。
如果要运行此类测试,则应在测试方法结束时保留已创建的线程集合以及join()
每个线程。每个线程的join()
调用在第二个循环中执行(在启动所有线程的循环之后)。
这样的事情:
@Test
public void testCalculator() {
List<Thread> threads = new ArrayList<>();
for (int i = 1; i < 21; i++) {
calculator = new Calculator(i);
thread = new Thread(calculator);
threads.add(thread);
System.out.println(thread.getName() + " Created");
thread.start();
System.out.println(thread.getName() + " Started");
}
for (Thread thread : threads) {
thread.join();
}
}
如果你想让所有的线程都在同一时间开始(例如,如果你创建线程的循环每次循环都会做一些非常重要的工作):
@Test
public void testCalculator() {
List<Thread> threads = new ArrayList<>();
for (int i = 1; i < 21; i++) {
threads.add(new Thread(new Calculator(i)));
}
for (Thread thread : threads) {
thread.start();
}
for (Thread thread : threads) {
thread.join();
}
}