Java 在多线程环境中使用JUnit的奇怪问题

Java 在多线程环境中使用JUnit的奇怪问题,java,multithreading,junit,Java,Multithreading,Junit,在多线程环境中使用JUnit时,我遇到了一个奇怪的问题。下面的代码应该失败,但它实际上在eclipse中传递 public class ExampleTest extends TestCase { private ExecutorService executor = Executors.newFixedThreadPool(10); private volatile boolean isDone = false; public void test() throws

在多线程环境中使用JUnit时,我遇到了一个奇怪的问题。下面的代码应该失败,但它实际上在eclipse中传递

public class ExampleTest extends TestCase {

    private ExecutorService executor = Executors.newFixedThreadPool(10);

    private volatile boolean isDone = false;

    public void test() throws InterruptedException, ExecutionException {
        executor.submit(new Runnable() {

            @Override
            public void run() {
                try {
                    fail();
                } finally {
                    isDone = true;
                }
            }
        });

        while (!isDone) {
            Thread.sleep(1000);
        }
    }
}
这是另一段代码,我使用Future.get()等待线程停止,在这种情况下它将失败

public class ExampleTest extends TestCase {

    private ExecutorService executor = Executors.newFixedThreadPool(10);

    private volatile boolean isDone = false;

    public void test() throws InterruptedException, ExecutionException {
        Future future=executor.submit(new Runnable() {

            @Override
            public void run() {
                try {
                    fail();
                } finally {
                    isDone = true;
                }
            }
        });

        future.get();
    }
}
我在谷歌上搜索了一下,发现JUnit无法处理多线程单元测试,但这两段代码之间有什么区别?谢谢

看一看(从17:09开始),它解释了JUnit和线程可能遇到的问题


我认为,在您的情况下,
get()
抛出一个
ExecutionException
,这就是第二个测试失败的原因。在第一个测试用例中,jUnit没有看到异常。

jUnit无法看到除运行测试的线程之外的其他线程中发生的异常。在第一种情况下,通过调用
fail
发生异常,异常发生在
执行器运行的单独线程中。因此它对JUnit不可见,并且测试通过


在第二种情况下,相同的异常发生在由
执行器运行的单独线程中,但是当您调用
future.get
时,该异常会有效地“报告回”测试线程。这是因为
future.get
如果由于任何异常而导致未来计算失败,则抛出
ExecutionException
。JUnit能够看到此异常,因此测试失败。

还有一个有趣的事实,Eclipse和IDEA可以在JUnit测试运行程序中生成VM,并最终调用system.exit()。这意味着如果您在测试中没有正确等待(就像您在上面睡觉并希望任务已完成时的情况一样),它可能会意外退出。有意思,但不完全是你要的


请参阅此以了解详细信息

正如@abhin4v所指出的,新线程中的异常会被吞没。您可以尝试提供自己的
fail
——与顶级线程同步的方法,非常类似于您的示例中的
get()


但是不需要使用未来,只需写入一个表示失败的共享变量,然后使用
newThreadId.join()
。除此之外,我不知道在普通JUnit中还有什么其他方法可以解决这个问题。

@zjffdu@ShiDoiSi指出,如果您有一个要断言或失败的工作线程,Thread.join()可以正常工作

如果您有多个工作线程,或者您希望更方便一些,那么有一个JUnit扩展用于执行多线程断言:

祝你好运

public class ExampleTest extends ConcurrentTestCase {
    private ExecutorService executor = Executors.newFixedThreadPool(10);

    public void test() throws Throwable {
        executor.submit(new Runnable() {
            @Override
            public void run() {
                try {
                    threadFail("Failure message");
                } finally {
                    resume();
                }
            }
        });

        threadWait();
    }
}