非守护程序线程输出有时会消失,直到使用join()

时间:2018-06-27 01:18:05

标签: java multithreading junit junit4 println

我仅使用两个线程进行了一次小型测试,如下所示:

print(f'Number {x:02x}')

有时候,输出包括其中之一,在我开始介绍import static java.lang.System.out; @Test public void testTwoSimpleThreads() { doInParallelAsync(() -> { out.println("First Ok"); }, () -> { out.println("Second Ok"); }); } private void doInParallelAsync(Runnable first, Runnable second) { new Thread(() -> { first.run(); }).start(); new Thread(() -> { second.run(); }).start(); } 之后,它们会开始。

到目前为止,我遇到了两个不同的输出:

一个

join()

两个

First Ok

我知道First Ok Second Ok 同步的,而且我知道 main 线程创建的线程默认是用户线程,而用户线程不会退出,直到完成。

尽管我使用的是 @Test ,但我测试了它们是否像预期的那样是非守护进程

non-daemon

  

是守护程序线程,当且仅当创建线程是守护程序时

还有

  

Java虚拟机将继续执行线程,直到发生以下任何一种情况为止:

     
      
  1. 已调用Runtime类的退出方法,并且安全管理器已允许进行退出操作。

  2.   
  3. 不是守护程序线程的所有线程都已死亡,或者是从调用返回到run方法,或者是抛出了传播到run方法之外的异常。

    < / li>   

已更新

实际上,我知道答案指出什么,不知道为什么输出消失了?

我需要问的问题:

  1. 管道被主线程关闭了吗?

  2. 为什么?是否因为每个管道独立地绑定到一个线程?不分享? (该管道直到最后一个线程像引用计数一样被关闭-在没有人使用它之前,不会删除该文件)

  3. 最后一个问题:它是由JVM控制还是取决于操作系统?

管道似乎已被我提到的println()关闭。谢谢@meriton指出来。

结论

当我在普通 @Test中尝试此方法并直接在main()之后直接调用System.exit(0);时,输出与该输出完全相同使用start()时。

使用@Test(Junit)时,将不等待线程。有关更多详细信息,请检查JUnit test not executing all threads created within the testJUnit terminates child threads

这是@Alex Lockwood的解释,我个人更喜欢:

  

JUnit是一个单元测试框架...与Android框架一样,它具有一个主线程,从中可以调用用户定义的单元测试方法。当单元测试返回时,JUnit立即调用下一个单元测试方法(如果没有更多要调用的单元测试方法,则JUnit完全退出)。 JUnit对您创建/启动的后台线程一无所知,因此您不能假设它会停滞不前并等待它们完成。

2 个答案:

答案 0 :(得分:2)

那是因为您是在不同的线程上启动它们的,而main thread不必等待child threads完成,而是将在最后一行之后立即关闭其执行。

因此,到那时,如果执行了线程1,输出将是:

First Ok

如果执行了线程2:

Second Ok

如果运气好的话都被执行了,那么

First Ok 
Second Ok

Second Ok 
First Ok

通过提供join,您是在要求main thread等待child thread完成并因此等待两个输出。

-编辑-

这并不意味着子线程已终止,它们仍然完成了执行,但由于此时可能已关闭或释放了外流,因此您可能看不到结果

如果在Jshell上执行相同的命令,则始终会得到第二个输出,但是有时它会作为另一个命令进入,因为一旦主线程完成,Jshell就会移至下一个命令行:

enter image description here

答案 1 :(得分:2)

在所有测试运行之后,测试运行程序是否可以调用System.exit()?如果将测试转换为普通的main()方法,可以重现部分输出吗?

(我会尝试一下,但在Eclipse中作为JUnit测试运行时无法重现部分输出)

...而且不,System.out是一个静态字段,因此被所有线程共享。退出主线程不会关闭流。