Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/hadoop/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Multithreading JUnit测试未执行测试中创建的所有线程_Multithreading_Junit4 - Fatal编程技术网

Multithreading JUnit测试未执行测试中创建的所有线程

Multithreading JUnit测试未执行测试中创建的所有线程,multithreading,junit4,Multithreading,Junit4,我写了一个简单的线程示例,它为从1到20的数字生成表格。当我用main方法测试它时,它会执行所有线程(打印所有消息),而在JUnit测试中,大多数情况下(有时它会运行所有线程),所有线程都没有运行(没有打印所有消息)。我认为产量不应该有任何差别 下面是使用main方法的类: public class Calculator implements Runnable { private int number; Calculator(final int number){

我写了一个简单的线程示例,它为从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");
        }

     }

}
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执行器完成时,所有生成的线程都将被杀死

如果要运行此类测试,应在测试方法结束时保留已创建的线程的集合,并将每个线程
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();
    }
 }
@测试
公共void testCalculator(){
List threads=new ArrayList();
对于(int i=1;i<21;i++){
计算器=新计算器(i);
线程=新线程(计算器);
线程。添加(线程);
System.out.println(thread.getName()+“Created”);
thread.start();
System.out.println(thread.getName()+“Started”);
}
用于(线程:线程){
thread.join();
}
}
如果希望所有线程都在同一时间启动(例如,如果创建线程的循环每次都在循环中执行一些非平凡的工作):

@测试
公共void testCalculator(){
List threads=new ArrayList();
对于(int i=1;i<21;i++){
添加(新线程(新计算器(i));
}
用于(线程:线程){
thread.start();
}
用于(线程:线程){
thread.join();
}
}

JUnit将提前退出测试方法。在退出
testCalculator()
方法之前,需要等待所有线程完成

一种简单的方法是使用
倒计时闩锁

  • 使用
    CountDownLatch-latch=new CountDownLatch(20)
    初始化一个
    CountDownLatch

  • 向每个
    计算器传递一个对闩锁的引用。在
    run()
    方法的末尾,调用
    lack.countDown()

  • testCalculator()
    方法调用
    latch.await()
    的末尾。这将一直阻止,直到调用了20次
    latch.countDown()
    (即当所有线程都已完成时)


  • 但这不会利用并行性。。。一次只能运行一个线程。有很多方法可以解决这个问题,可以使用
    CountDownLatch
    ExecutorService#invokeAll(List)
    方法。所有线程都在现有循环中调用了
    start()
    。答案是在测试方法的末尾添加第二个循环,在每个派生线程上调用
    join()
    join()
    调用在该线程完成之前不会返回。充分利用并行性并确保在返回之前完成所有生成的线程。CountDownLatch需要仔细编码,以确保即使有异常,每个线程也会倒计时。ExecutorService仍然要求您等待可调用(或可运行)完成。啊,好的。我同意使用
    join()
    。您可能希望在回答中澄清“方法末尾的第二个循环”。不过,使用
    countdownlock
    可以很好地用于OP(在
    计算器中不会抛出异常。而
    ExecutorService
    甚至可能是这里的最佳选择,因为无论在哪台计算机上执行,您都可以使用
    Runtime.getRuntime().availableProcessor()
    threads来创建线程池,而不是创建20个线程。然后调用
    invokeAll()
    将执行所有可调用项,并将阻止它们,直到它们全部完成。感谢您的回复。现在尝试你的建议:)我尝试了你的方法。很好用。但是我想知道为什么在主方法的情况下线程是活动的并且正在运行的,而在JUnit方法的情况下它不像在主方法中那样发生。谢谢你的回复。我试试看。好的。我明白你的意思,但我仍然无法理解为什么主线程会等待它启动的所有线程完成/完成,而JUnit测试线程却不允许这样做。你能解释一下吗?你是在问倒计时闩锁是怎么工作的吗?或者您是在问为什么需要阻塞直到所有线程都完成?不是关于倒计时锁存,而是关于主线程和运行测试方法的JUnit线程之间的差异。为什么两者行为不同?JUnit是一个单元测试框架。。。与Android框架一样,它有一个主线程,可以从中调用用户定义的单元测试方法。当单元测试返回时,JUnit立即调用下一个单元测试方法(如果没有更多的单元测试方法可调用,则完全退出)。JUnit对您创建/启动的后台线程一无所知,因此您不能假设它会坐等它们完成。这有意义吗?
    @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();
        }
    }