这个问题也可以换个说法,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等方法.