代码之家  ›  专栏  ›  技术社区  ›  Hearen

在使用join()之前,非守护进程线程输出有时会消失

  •  1
  • Hearen  · 技术社区  · 7 年前

    我有个小测试 两条线 具体如下:

    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
    

    我知道 println() 同步的 我也知道 主要的 线程在默认情况下是用户线程,用户线程将 不退出 直到他们结束。

    尽管我在用 @测试 ,我测试过他们 非后台程序 如预期。

    non-daemon

    是后台程序线程,如果且仅当创建线程是后台程序

    以及

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

    1. 类运行时的exit方法已被调用,安全管理器已允许执行exit操作。

    2. 所有线程 不是守护进程线程 通过从调用返回run方法或引发传播到run方法之外的异常而死亡。

    更新

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

    我需要问的问题:

    1. 这个 管道 被主线封闭?

    2. 为什么?是不是因为每条管道都独立地连接到一个线程上?不共享?(直到最后一个线程完成,管道才会关闭,就像 参考计数 -除非无人使用,否则不会删除该文件)

    3. 最后一个问题:它是由jvm控制还是依赖于os?

    看来 管道 被关闭 @Test 我提到过。“谢谢你,”梅里顿指出。

    结论

    当我在一个 普通的 main() ,并直接调用 System.exit(0); 就在 start() ,输出与使用 @测试 是的。

    使用时 @测试 (junit),线程不会等待。详情请查收 JUnit test not executing all threads created within the test JUnit terminates child threads 是的。

    以下是@alex lockwood的解释,我个人更喜欢:

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

    2 回复  |  直到 7 年前
        1
  •  2
  •   meriton    7 年前

    测试运行程序是否调用 System.exit() 在所有测试运行之后?如果将测试转换为普通的 main() 方法?

    (我自己尝试过,但在eclipse中作为junit测试运行时无法复制部分输出)

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

        2
  •  2
  •   Aman Chhabra    7 年前

    那是因为你从另一条线开始 main thread 不要等待 child threads 完成并将在最后一行之后立即关闭其执行。

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

    First Ok
    

    如果执行线程2:

    Second Ok
    

    如果两人都被执行死刑

    First Ok 
    Second Ok
    

    Second Ok 
    First Ok
    

    通过提供 join ,你在问 主螺纹 等待 child thread 完成,因此两个输出。

    --编辑--

    这并不意味着子线程已经终止,它们仍然完成了它们的执行,但是您可能无法看到结果,因为此时outstream可能已经关闭或释放。

    如果在jshell上执行相同的命令,您将始终获得第二个输出,但有时它会作为另一个命令传入,因为只要主线程完成,jshell就会移到下一个命令行:

    enter image description here