17

我正在尝试编写一个需要多个线程的单元测试。但是,线程似乎只是在执行过程中停止了一部分。考虑以下代码:

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

如果我运行这个单元测试,它通常会在 140-180 之间停止显示输出。如果我将此代码转换为常规类并运行它,它可以正常工作。有人知道我在这里缺少什么吗?

谢谢, - 安德鲁。

4

3 回答 3

27

您可以使用它Thread.join()来阻止测试在新线程完成其任务之前完成:

@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();
}

通常,JVM 将在最后一个非守护线程终止时终止。您可能期望简单地调用t.setDaemon(false)线程会阻​​止 JVM 在任务完成之前退出。但是,当主线程完成时,junit 将调用System.exit()。

正如 Gus 在评论中指出的那样:“你需要 join() 因为 start() 不会阻塞”。

他是正确的,你也可以run()在这个最小的例子中调用。但是,我假设您正在启动一个线程,因为您希望它与另一个线程同时运行。FindBugs 将调用run()线程标记为可能的错误 - 如果您只是要调用run(),您可能只想实现 Runnable 而不是使用线程。

于 2013-05-17T19:45:36.860 回答
6

在该TestThread函数中,JUnit 无法告诉您生成了一个新线程。一旦函数结束(到达最后一行)并且不知道线程,它就会回收它在函数中创建的任何对象。

出于这个原因,您会看到线程的输出,直到它被杀死。如果你想等待线程完成,你可以使用Thread.join(在你调用之后Thread.start())让它等待结果或wait-notify在某个对象上使用。

另外,发现了这个问题:JUnit terminates child threads

于 2013-05-17T19:40:44.430 回答
0

可能是运行测试的父线程正在完成。如果可以避免,请不要在测试中创建新线程。我将创建一个实现 runnable 的新类,然后在该对象上简单地调用 run 来测试该类。作为测试的一部分,您不需要测试线程调度。希望java语言开发团队已经涵盖了:)

于 2013-05-17T19:39:06.827 回答