首页 > 编程语言 >Go 和 Java 程序退出机制的区别

Go 和 Java 程序退出机制的区别

时间:2022-09-23 21:34:17浏览次数:54  
标签:Java goroutine 程序 线程 Go 结束 main 守护

前情提要

写这篇随笔的原因是最近在写 mit 6.824的 lab1,实验中使用 rpc 作为 coordinator 和 worker 的通信方式。因为之前一直使用 Java,所以就想对比一下两种语言的退出机制,也算是对 Java 理解的巩固。



Java 机制

Java 有两种线程:

  • 非守护线程(用户线程):比如 main 方法就是一个非守护线程
  • 守护线程:服务于其他线程的线程(这个思想很重要,后面会再提到),不需要上层逻辑介入。如果其他非守护线程都已经结束,守护线程没有了服务对象,那么守护线程也就退出了。
    • 我理解的“不需要上层逻辑介入”:其实就是守护线程根本不关心创建它的上层线程具体做什么,虽然依赖上层线程,但是守护线程只关心自己做什么,也不需要上层线程介入。比如后面提到的“GC 垃圾回收线程”。


用户线程和守护线程的区别:

  • 在一个 JVM 实例中,当所有的用户线程运行结束后,JVM 退出,当前的进程结束(如果调用了 System.exit()方法,即使还有非守护线程正在执行,那么 JVM 也会退出)
  • 如果一个线程是守护线程,即使该线程没有运行结束,但是所有的用户线程已经运行完,JVM 仍旧会退出。


如何设置守护线程:

调用 Thread 的 setDaemon() 方法,这个方法默认是false:

public class TestThread {
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        Thread thread = new Thread(myThread);
        thread.setDaemon(true);
        thread.start();
        System.out.println("world");
    }

    static class MyThread implements Runnable {
        @Override
        public void run() {
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("hello");
        }
    }
}

在上面的 demo 中,MyThread 被设置为守护线程,那么 main 方法输出 “world” 之后整个程序就退出了,而不会继续打印 “hello”。

如果不设置为守护线程,那么上面的 demo 会正常地输出 hello,在 sleep 5 秒之后。



守护线程的使用场景

  • GC 垃圾回收线程:垃圾回收线程就是用于回收其他用户线程产生的垃圾,垃圾回收线程就是服务于其他用户线程。如果所有的用户线程都运行结束,那么垃圾回收线程也就没有存在的必要了。


注意事项

守护线程不能持有任何需要关闭的资源,例如打开文件等,因为虚拟机退出时,守护线程没有任何机会来关闭文件,这会导致数据丢失。



go 机制

在 go 语言中,一定要注意的是, goroutine 以非阻塞的方式执行,它们会随着程序(main goroutine)的结束而消亡。也就是说,当main 函数执行结束后,那么所有由 main 函数产生的 goroutine 也会结束,即使 goroutine 没有执行完。

如果一个 goroutine B 不是由 main 函数产生,而是由另外一个 goroutine A 产生。在 main 函数没有执行结束的前提下,那么即使 A 结束了,B 也不会结束。

所以,在 go 中,如果想要等待所有 goroutine 执行结束再退出,就需要使用其他手段了,比如sync 包中提供了 WaitGroup 类型。

标签:Java,goroutine,程序,线程,Go,结束,main,守护
From: https://www.cnblogs.com/supportmyself/p/15648757.html

相关文章