浅谈java中守护线程与用户线程
作者:今天你不奋斗明天你就落后 发布时间:2023-11-26 20:46:41
Java线程分为两类分别为daemon线程(守护线程)和User线程(用户线程),在JVM启动时候会调用main函数,main函数所在的线程是一个用户线程,这个是我们可以看到的线程,其实JVM内部同时还启动了好多守护线程,比如垃圾回收线程。那么守护线程和用户线程有什么区别那?区别之一是当最后一个非守护线程结束时候,JVM会正常退出,而不管当前是否有守护线程,也就是说守护线程是否结束并不影响JVM的退出。言外之意是只要有一个用户线程还没结束正常情况下JVM就不会退出。
那么Java中如何创建一个守护线程那?代码如下:
public static void main(String[] args) {
Thread daemonThread = new Thread(new Runnable() {
public void run() {
}
});
//设置为守护线程
daemonThread.setDaemon(true);
daemonThread.start();
}
可知只需要设置线程的daemon参数为true即可。
下面通过例子来加深用户线程与守护线程的区别的理解,首先看下面代码:
public static void main(String[] args) {
Thread thread = new Thread(new Runnable() {
public void run() {
for(;;){}
}
});
//启动子线
thread.start();
System.out.print("main thread is over");
}
结果输出为:
如上代码在main线程中创建了一个thread线程,thread线程里面是无限循环,运行代码从结果看main线程已经运行结束了,那么JVM进行已经退出了?从IDE的输出结果右侧上的红色方块说明JVM进程并没有退出,另外
mac上执行ps -eaf | grep java会输出结果,也可以证明这个结论。
这个结果说明了当父线程结束后,子线程还是可以继续存在的,也就是子线程的生命周期并不受父线程的影响。也说明了当用户线程还存在的情况下JVM进程并不会终止。那么我们把上面的thread线程设置为守护线程后在运行看看会有什么效果:
//设置为守护线程
thread.setDaemon(true);
//启动子线
thread.start();
执行结果为:
如上在启动线程前设置线程为守护线程,从输出结果可知JVM进程已经终止了,执行ps -eaf |grep java 也看不到JVM进程了。这个例子里面main函数是唯一的用户线程,thread线程是守护线程,当main线程运行结束后,JVM发现当前已经没有用户线程了,就会终止JVM进程。
Java中在main线程运行结束后,JVM会自动启动一个叫做DestroyJavaVM线程,该线程会等待所有用户线程结束后终止JVM进程,下面通过简单的JVM代码来证明这个结论:
翻开JVM的代码,最终会调用到JavaMain这个c函数
int JNICALL
JavaMain(void * _args)
{
...
//执行Java中的main函数
(*env)->CallStaticVoidMethod(env, mainClass, mainID, mainArgs);
//main函数返回值
ret = (*env)->ExceptionOccurred(env) == NULL ? 0 : 1;
//等待所有非守护线程结束,然后销毁JVM进程
LEAVE();
}
LEAVE是c语言里面的一个宏定义,定义如下:
#define LEAVE() \
do { \
if ((*vm)->DetachCurrentThread(vm) != JNI_OK) { \
JLI_ReportErrorMessage(JVM_ERROR2); \
ret = 1; \
} \
if (JNI_TRUE) { \
(*vm)->DestroyJavaVM(vm); \
return ret; \
} \
} while (JNI_FALSE)
上面宏的作用实际是创建了一个名字叫做DestroyJavaVM的线程来等待所有用户线程结束。
总结:如果你想在主线程结束后JVM进程马上结束,那么创建线程的时候可以设置线程为守护线程,否者如果希望主线程结束后子线程继续工作,等子线程结束后在让JVM进程结束那么就设置子线程为用户线程,开源框架Tomcat中就是用了守护线程和用户线程联合运行起来的,具体敬请期待Java并发编程基础之并发包源码剖析一书出版。
来源:http://www.jianshu.com/p/c9e3001cd821?utm_source=tuicool&utm_medium=referral


猜你喜欢
- 性能优化点:1.使用int不使用double。(单位用分不用元)也省去了还要用math.round四舍五入,把double类型数据只留小数点
- 前言直接使用项目或直接复制libs中的so库到项目中即可(当前只构建了armeabi),需要其他ABI可检下项目另外使用CMake构建即可。
- 之前一直使用各种报表工具,如RDLC、DevExpress套件的XtraReport报表,在之前一些随笔也有介绍,最近接触锐浪的Grid++
- 前言 短时间提升自己最快的手段就是背面试题,最近总结了Java常用的面试题,分享给大家,希望大家都能圆梦大厂,加油,我命由我不由天
- 节点通信存在两种模型:共享内存(Shared memory)和消息传递(Messages passing)。内存映射文件对于托管世界的开发人
- 本文汇总了C#启动外部程序的几种常用方法,非常具有实用价值,主要包括如下几种方法:1. 启动外部程序,不等待其退出。2. 启动外部程序,等待
- 🍊一. 为什么需要线程通信线程是并发并行的执行,表现出来是线程随机执行,但是我们在实际应用中对线程的执行顺序是有要求的,这就需要用到线程通信
- C# 从枚举值获取对应的文本描述详解有时枚举值在显示时,需要显示枚举值对应的文本串。一种方案是在调用的地方使用switch或者if来判断枚举
- 一、内部类的概念在 Java 中,可以将一个类定义在另一个类或者一个方法的内部,前者称为内部类,后者称为外部类。内部类也是封装的一种体现。p
- C#申请一个大数组(Use a large array in C#)在C#里,有时候我需要能够申请一个很大的数组、使用之、然后立即释放其占用
- 本文实例讲述了Android开发之获取LayoutInflater对象的方法。分享给大家供大家参考,具体如下:在写Android程序时,有时
- 什么是Stream流?Stream流是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。Stream的优点:声明性,可复合,可并行。
- 控制json序列化/反序列化1. @JsonIgnoreProperties的用法@JsonIgnoreProperties(value =
- 需求:传入多个 id 查询用户信息,用下边两个 sql 实现:SELECT * FROM USERS WHERE username LIKE
- java8的stream取max public static void main(String[] args) { &
- Java语言是简单的:Java语言的语法与C语言和C++语言很接近,使得大多数程序员很容易学习和使用。另一方面,Java丢弃了C++中很少使
- 目录1.加载本地Word2.以只读模式加载Word3.从流加载Word【程序环境】Windows 10Visual Studio 2017W
- 本文实例讲述了Android编程单选项框RadioGroup用法。分享给大家供大家参考,具体如下:今天介绍的是RadioGroup 的组事件
- 本文实例总结了Android实现计时与倒计时的常用方法。分享给大家供大家参考,具体如下:方法一Timer与TimerTask(Java实现)
- Java实现基于Socket的简单通信 一.ServerSocket1.使用JavaFX写的小界面,方便观察客户端连接情况 &nb