main线程终止,其他线程还会运行吗?

5,302 阅读2分钟

这个问题也可以换个说法,main线程是最后退出的线程吗?

理论分析

当你启动一个Java Application的时候,这个时候系统创建一个进程,分配各项资源,然后这个进程启动了Main线程.

我们一般把Main线程说成主线程,因为其他线程一般是由main线程启动的.

但其实,在进程层面看起来,main其实也是一个普通的线程.只不过一些其他的线程都是由main启动的.

我们可以猜想一下:正常情况下,main线程启动了其他线程,他们各自执行,彼此不受影响.

猜想依据:因为操作系统分配资源的单位是进程,就算main线程退出了,进程也还在.资源还在.在进程看来,线程应该都是平级的,没有父子关系.

实践验证

我们模拟一个线程池的例子,从main线程启动一个线程池,当发生异常,则让main线程抛出异常终止,看看线程池是否还继续运行.

这里由于网上有些争论认为打印的方式无法判断main线程是否终止,所以我们的示例使用异常终止,并且使用jconsole工具进行验证.

public class ThreadPoolException {
    ExecutorService threadPool = Executors.newFixedThreadPool(5);
    public static void main(String[] args) {
        ThreadPoolException t = new ThreadPoolException();
        t.futureGet();
    }

    void futureGet() {
        for (int i = 0; i < 5; i++) {
            Future future = threadPool.submit(() -> {
                System.out.println("current thread name" + Thread.currentThread().getName());
                Object object = null;
                System.out.print("result## " + object.toString());
            });
            try {
                future.get();
            } catch (Exception e) {
                System.out.println(Thread.currentThread().getName() + "异常");
                // 让主线程多等一段时间,便于观察.
                try {
                    Thread.sleep(10000);
                } catch (InterruptedException e1) {
                    e1.printStackTrace();
                }
                //主线程终止
                throw new RuntimeException(Thread.currentThread().getName() + "异常");
            }
        }
    }
}		

我们可以在jconsole中观察到:

在main线程先出现然后会消失,线程池中的线程还在,只不过是wait状态. 在idea中直接运行代码,也可以观察到同样的结论.

总结

  • JVM会在所有的非守护线程(用户线程)执行完毕后退出;
  • main线程是用户线程;
  • 仅有main线程一个用户线程执行完毕,不能决定JVM是否退出,也即是说main线程并不一定是最后一个退出的线程。

如果你希望在main线程退出后,所有其他线程也退出.那么你可以把其他线程都设置为守护线程,也就是setDaemon(true). 对于线程池,你可以在main线程退出的的时候手动进行一些处理.比如shutdown等方法.