JUnit中线程表现异常

18

我正在尝试编写一个需要多个线程的单元测试。但是,似乎线程在执行到一半就停止了。请看以下代码:

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 的某个地方停止显示输出。如果我将此代码转换为常规类并运行它,则可以正常工作。有人知道我在这里缺失了什么吗?
谢谢, - 安德鲁。
3个回答

28
你可以使用 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将call System.exit()。

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

他正确地指出,您还可以在此最小示例中调用run()。但是,我假设您启动线程是因为您希望它与另一条线程并发运行。在线程上调用run()被FindBugs标记为可能的错误 - 如果您只想调用run(),您可能只需要实现Runnable而不是使用Thread。


唉,你公平地抢先一步了。 - Bob Cross
1
在你的解决方案中值得一提的是,你需要使用Join(),因为Start()不会阻塞。如果你不打算同时执行任何操作,也可以只使用Run()。 - Gus
谢谢,这正是问题所在。run()函数可以正常工作,但却无法实现我需要进行的多线程测试。也许你能看出来,这是我第一次编写多线程Java程序。 - Andrew Clarke
@AndrewClarke 使用 run 就像在类中调用一个普通方法。使用 start 会告诉 JVM:“嘿!有一个新的真实线程想要独立于主应用程序线程运行”。FindBugs将其标记为“可能”的错误是因为在 Thread 上调用 run 应该是一个错误(在我看来它是一个错误),它应该从 JVM 被调用,而不是从程序员那里。 - Luiggi Mendoza
1
我猜这取决于你是想测试方法还是线程。 - Gus
显示剩余2条评论

6
TestThread函数中,JUnit无法知道您是否创建了一个新线程。它在函数结束时(即最后一行代码执行完毕时)就回收了函数中创建的任何对象,而且不知道该线程的存在。
因此,您会看到线程输出,直到它被终止为止。如果您想等待线程完成,可以使用Thread.join(在调用Thread.start()之后立即调用)来等待结果,或者在某个对象上使用wait-notify
另外,发现了这个问题:JUnit terminates child threads

在Java中,说JUnit会“删除”对象有点误导,因为没有明确删除对象的方法。 - Martin Ellis
@Martin 没错。但是当对象不再需要时,JVM可以回收(GC)。一旦测试完成,JUnit会终止线程并基本上关闭整个JVM。 - goblinjuice
@goblinjuice 这并不意味着JUnit会杀死一个对象实例。由于JVM退出,每个使用的内存位都将被释放。 - Luiggi Mendoza
它只是调用System.exit。我的答案中有源代码的链接。 - Martin Ellis

0

很可能是运行测试的父线程正在结束。如果可以避免,那么不要在测试中创建新线程。我会创建一个实现Runnable接口的新类,然后通过调用该对象上的run方法来测试该类。您不应该需要将线程调度作为测试的一部分。希望Java语言开发团队已经考虑到了这一点 :)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接