浅谈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");
 }

结果输出为:

浅谈java中守护线程与用户线程

如上代码在main线程中创建了一个thread线程,thread线程里面是无限循环,运行代码从结果看main线程已经运行结束了,那么JVM进行已经退出了?从IDE的输出结果右侧上的红色方块说明JVM进程并没有退出,另外
mac上执行ps -eaf | grep java会输出结果,也可以证明这个结论。

这个结果说明了当父线程结束后,子线程还是可以继续存在的,也就是子线程的生命周期并不受父线程的影响。也说明了当用户线程还存在的情况下JVM进程并不会终止。那么我们把上面的thread线程设置为守护线程后在运行看看会有什么效果:


   //设置为守护线程
   thread.setDaemon(true);
   //启动子线
   thread.start();

执行结果为:

浅谈java中守护线程与用户线程

如上在启动线程前设置线程为守护线程,从输出结果可知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

标签:java,守护线程,用户线程
0
投稿

猜你喜欢

  • java中Class.getMethods()和Class.getDeclaredMethods()方法的区别

    2021-05-28 23:05:46
  • Spring Boot如何通过自定义注解实现日志打印详解

    2022-07-04 14:10:18
  • Android自定义Seekbar滑动条 Pop提示跟随滑动按钮滑动

    2021-11-02 20:32:06
  • 详解JAVA里面获取map的key和value的方法

    2023-04-27 03:11:50
  • kotlin之协程的理解与使用详解

    2023-10-21 15:55:57
  • 通过spring boot 设置tomcat解决 post参数限制问题

    2022-09-26 23:38:31
  • java使用listIterator逆序arraylist示例分享

    2022-06-16 05:33:10
  • AndroidStudio kotlin配置详细介绍

    2022-02-18 14:09:21
  • Android常用的数据加密方式代码详解

    2022-07-24 14:30:06
  • C#中文随机数实现方法

    2023-12-07 20:56:30
  • java数据结构和算法学习之汉诺塔示例

    2021-09-28 14:46:18
  • SpringBoot如何优雅地处理全局异常详解

    2023-01-06 04:30:19
  • JAVA实现PDF转HTML文档的示例代码

    2021-10-18 12:47:00
  • Java抽象类与接口区别详解

    2021-06-19 19:22:37
  • 在Struts2中如何将父类属性序列化为JSON格式的解决方法

    2022-08-01 09:30:34
  • C#中Json的简单处理方法

    2022-05-19 05:25:14
  • Android自定义ProgressDialog进度等待框

    2022-07-09 13:51:46
  • android开发去除标题栏的方法

    2021-06-30 19:11:29
  • Netty分布式高性能工具类异线程下回收对象解析

    2023-07-09 21:02:43
  • 浅析SpringCloud Alibaba-Nacos 作为注册中心示例代码

    2022-12-04 14:24:00
  • asp之家 软件编程 m.aspxhome.com