【问题标题】:Thread behaving strangely in JUnit线程在 JUnit 中表现异常
【发布时间】:2013-05-17 19:33:01
【问题描述】:

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

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 之间停止显示输出。如果我将此代码转换为常规类并运行它,它可以正常工作。有人知道我在这里缺少什么吗?

谢谢, - 安德鲁。

【问题讨论】:

    标签: java multithreading junit


    【解决方案1】:

    您可以使用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 会callSystem.exit()。

    正如 Gus 在 cmets 中所说:“你需要 join() 因为 start() 不会阻塞”。

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

    【讨论】:

    • 叹息 - 让我一拳打死。
    • 在您的解决方案中值得一提的是,您需要 Join() 因为 Start() 不会阻塞。 IIRC,如果你不打算同时做任何事情,你也可以只使用 Run()。
    • @Gus 在Thread 实例上使用run 是个坏主意。为什么?因为使用run 并不能使它成为一个线程,而只是一个普通的对象。
    • 谢谢,这正是问题所在。 run() 工作正常,但否定了我测试所需的多线程。您可能会说这是我第一次编写多线程 Java 程序。
    • 我想这取决于您是打算测试方法还是线程
    【解决方案2】:

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

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

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

    【讨论】:

    • 说 JUnit '删除'对象有点误导,因为在 Java 中,没有办法显式删除对象。
    • @Martin 对。但是当不再需要对象时,JVM 可以回收(GC)。测试完成后,JUnit 会杀死线程,基本上会杀死整个 JVM。
    • @goblinjuice 这并不意味着 JUnit 根本就杀死了一个对象实例。由于 JVM 退出,使用的每个内存位都将被释放。
    • 它只是调用 System.exit。我的答案中有一个指向来源的链接。
    【解决方案3】:

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

    【讨论】:

      猜你喜欢
      • 2021-12-14
      • 1970-01-01
      • 2013-10-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-08-31
      • 2014-10-27
      相关资源
      最近更新 更多