在Java中通常有两种线程:用户线程守护线程(也被称为服务线程)
通过Thread.setDaemon(false)设置为用户线程
通过Thread.setDaemon(true)设置为守护线程
线程属性的设置要在线程启动之前,否则会报IllegalThreadStateException异常
如果不设置线程属性,那么默认为用户线程

用户线程和守护线程的区别:
 1.主线程结束后用户线程还会继续运行,JVM存活
 2.如果没有用户线程,都是守护线程,那么JVM结束(所有的线程都会结束)

  守护进程(Daemon)是运行在后台的一种特殊进程。它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。也就是说守护线程不依赖于终端,但是依赖于系统,与系统“同生共死”。那Java的守护线程是什么样子的呢。当JVM中所有的线程都是守护线程的时候,JVM就可以退出了;如果还有一个或以上的非守护线程则JVM不会退出。


  守护线程是一种特殊的线程,在后台默默地完成一些系统性的服务,比如垃圾回收线程JIT线程都是守护线程。与之对应的是用户线程,用户线程可以理解为是系统的工作线程,它会完成这个程序需要完成的业务操作。如果用户线程全部结束了,意味着程序需要完成的业务操作已经结束了,系统可以退出了。所以当系统只剩下守护进程的时候,java虚拟机会自动退出

java线程分为用户线程和守护线程,线程的daemon属性为true表示是守护线程,false表示是用户线程。

下面我们来看一下守护线程的一些特性。

程序只有守护线程时,系统会自动退出

  1. public class Demo1 {
  2.  
  3. public static class T1 extends Thread {
  4. public T1(String name) {
  5. super(name);
  6. }
  7.  
  8. @Override
  9. public void run() {
  10. System.out.println(this.getName() + "开始执行," + (this.isDaemon() ? "我是守护线程" : "我是用户线程"));
  11. while (true) ;
  12. }
  13. }
  14.  
  15. public static void main(String[] args) {
  16. T1 t1 = new T1("子线程1");
  17. t1.start();
  18. System.out.println("主线程结束");
  19. }
  20. }

运行上面代码,结果如下:

可以看到主线程已经结束了,但是程序无法退出,原因:子线程1是用户线程,内部有个死循环,一直处于运行状态,无法结束。

再看下面的代码:

  1. public class Demo2 {
  2.  
  3. public static class T1 extends Thread {
  4. public T1(String name) {
  5. super(name);
  6. }
  7.  
  8. @Override
  9. public void run() {
  10. System.out.println(this.getName() + "开始执行," + (this.isDaemon() ? "我是守护线程" : "我是用户线程"));
  11. while (true) ;
  12. }
  13. }
  14.  
  15. public static void main(String[] args) {
  16. T1 t1 = new T1("子线程1");
  17. t1.setDaemon(true);
  18. t1.start();
  19. System.out.println("主线程结束");
  20. }
  21. }

运行结果:

程序可以正常结束了,代码中通过t1.setDaemon(true);将t1线程设置为守护线程,main方法所在的主线程执行完毕之后,程序就退出了。

结论:当程序中所有的用户线程执行完毕之后,不管守护线程是否结束,系统都会自动退出。

设置守护线程,需要在start()方法之前进行

  1. import java.util.concurrent.TimeUnit;
  2.  
  3. public class Demo3 {
  4.  
  5. public static void main(String[] args) {
  6. Thread t1 = new Thread() {
  7. @Override
  8. public void run() {
  9. try {
  10. TimeUnit.SECONDS.sleep(10);
  11. } catch (InterruptedException e) {
  12. e.printStackTrace();
  13. }
  14. }
  15. };
  16. t1.start();
  17. t1.setDaemon(true);
  18. }
  19. }

t1.setDaemon(true);是在t1的start()方法之后执行的,执行会报异常,运行结果如下:

线程daemon的默认值

我们看一下创建线程源码,位于Thread类的init()方法中:

  1. Thread parent = currentThread();
  2. this.daemon = parent.isDaemon();

dameon的默认值为为父线程的daemon,也就是说,父线程如果为用户线程,子线程默认也是用户现场,父线程如果是守护线程,子线程默认也是守护线程。

示例代码:

  1. import java.util.concurrent.TimeUnit;
  2.  
  3. public class Demo4 {
  4. public static class T1 extends Thread {
  5. public T1(String name) {
  6. super(name);
  7. }
  8.  
  9. @Override
  10. public void run() {
  11. System.out.println(this.getName() + ".daemon:" + this.isDaemon());
  12. }
  13. }
  14.  
  15. public static void main(String[] args) throws InterruptedException {
  16.  
  17. System.out.println(Thread.currentThread().getName() + ".daemon:" + Thread.currentThread().isDaemon());
  18.  
  19. T1 t1 = new T1("t1");
  20. t1.start();
  21.  
  22. Thread t2 = new Thread() {
  23. @Override
  24. public void run() {
  25. System.out.println(this.getName() + ".daemon:" + this.isDaemon());
  26. T1 t3 = new T1("t3");
  27. t3.start();
  28. }
  29. };
  30.  
  31. t2.setName("t2");
  32. t2.setDaemon(true);
  33. t2.start();
  34.  
  35. TimeUnit.SECONDS.sleep(2);
  36. }
  37. }

运行代码,输出:

  1. main.daemon:false
  2. t1.daemon:false
  3. t2.daemon:true
  4. t3.daemon:true

t1是由主线程(main方法所在的线程)创建的,main线程是t1的父线程,所以t1.daemon为false,说明t1是用户线程。

t2线程调用了setDaemon(true);将其设为守护线程,t3是由t2创建的,所以t3默认线程类型和t2一样,t2.daemon为true。

守护线程适用场景

  针对于守护线程的特点,java 守护线程通常可用于开发一些为其它用户线程服务的功能。比如说心跳检测,事件监听等。Java 中最有名的守护进程当属GC(垃圾回收)

总结

  1. java中的线程分为用户线程守护线程
  2. 程序中的所有的用户线程结束之后,不管守护线程处于什么状态,java虚拟机都会自动退出
  3. 调用线程的实例方法setDaemon()来设置线程是否是守护线程
  4. setDaemon()方法必须在线程的start()方法之前调用,在后面调用会报异常,并且不起效
  5. 线程的daemon默认值和其父线程一样

java 用户线程和守护线程的更多相关文章

  1. Java用户线程和守护线程

    今天看Java一个关于多线程返回值方式的示例,发现一个自己不太能理解的问题,就是在主线程中启动了几个工作线程,主线程中也没有join,工作线程居然也是正常输出了回调的结果.这个跟linux C++下的 ...

  2. 【java多线程】用户线程和守护线程的区别

    java中线程分为两种类型:用户线程和守护线程.通过Thread.setDaemon(false)设置为用户线程:通过Thread.setDaemon(true)设置为守护线程.如果不设置次属性,默认 ...

  3. java高并发系列 - 第9天:用户线程和守护线程

    守护线程是一种特殊的线程,在后台默默地完成一些系统性的服务,比如垃圾回收线程.JIT线程都是守护线程.与之对应的是用户线程,用户线程可以理解为是系统的工作线程,它会完成这个程序需要完成的业务操作.如果 ...

  4. java并发:初探用户线程和守护线程

    用户线程和守护线程 用户线程 用户线程执行完,jvm退出.守护线程还是可以跑的 /** * A <i>thread</i> is a thread of execution i ...

  5. 额!Java中用户线程和守护线程区别这么大?

    在 Java 语言中线程分为两类:用户线程和守护线程,而二者之间的区别却鲜有人知,所以本文磊哥带你来看二者之间的区别,以及守护线程需要注意的一些事项. 1.默认用户线程 Java 语言中无论是线程还是 ...

  6. Java:多线程<四> Lock、停止线程、守护线程、join、优先级&yield

    Java1.5以后,Condition将Object监视器方法(wait, notify, notifyAll)分解成截然不同的对象,以便通过这些对象与任意Lock实现组合使用为每个对像提供多个等待s ...

  7. Java中的守护线程 & 非守护线程(简介)

    Java中的守护线程 & 非守护线程 守护线程 (Daemon Thread) 非守护线程,又称用户线程(User Thread) 用个比较通俗的比如,任何一个守护线程都是整个JVM中所有非守 ...

  8. Java多线程编程之守护线程

    Java的线程分为两种,一个是用户线程,一个是守护线程.守护线程守护的对象就是用户线程,当用户线程结束后,守护它的守护线程也就会结束.二者的本质基本是一样的,唯一区别在于何时结束. 用户线程:直到自己 ...

  9. JAVA笔记13__创建线程/线程休眠/等待线程终止/线程中断/守护线程

    /** * 线程:是进程的一个执行路径,共享一个内存空间,线程之间可以自由切换,并发执行,一个进程最少有一个进程(单线程程序) * 多线程两种实现方法:1.继承Thread类 2.实现Runnable ...

随机推荐

  1. opencv VS C++ 配置

    包含目录 $(OPENCV)\include\ $(OPENCV)\include\opencv\ $(OPENCV)\include\opencv2\   即: D:\opencv\opencv\b ...

  2. C++ STL介绍——String类

    目录 1.简介 2.string类成员函数汇总 3.String类的构造函数以及析构函数 4.获取字符串长度 5.获取字符串元素 6.字符串比较方法 7.字符串输入输出 8.字符串查找函数 1.简介 ...

  3. oracle的表分区

    (1.) 表空间及分区表的概念 表空间: 是一个或多个数据文件的集合,所有的数据对象都存放在指定的表空间中,但主要存放的是表, 所以称作表空间.   分区表: 当表中的数据量不断增大,查询数据的速度就 ...

  4. Mac中好用的快捷键

    1.safari safariy页面刷新:Command+R,类似于Win系统里面的F5

  5. LC 992. Subarrays with K Different Integers

    Given an array A of positive integers, call a (contiguous, not necessarily distinct) subarray of A g ...

  6. Linux中ctrl+z 、ctrl+c、 ctrl+d区别

    Ctrl + C 和Ctrl + Z都是中断命令,但是他们的作用却不一样. Ctrl + C 是强制中断程序的执行,进程已经终止. Ctrl + C 发送 SIGINT信号 参考:linux信号 Ct ...

  7. AFN使用etag进行网络缓存

    前提:后台返回的接口带etag 第一步 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( ...

  8. djando模板----第一django模板应用

    Django模板 我们已经知道,模板函数的函数的返回值就是返回给客户端的数据,但如果返回数据很复杂,如果一个非常大的html页面,直接将页面代码固化在python脚本文件中是不合适的,当然 也可以将h ...

  9. MySQL 5.7 源码中的目录结构

    MySQl Server的源码可以直接去Github浏览. 这里我们选择5.7版本的:https://github.com/mysql/mysql-server/tree/5.7 也可以通过: git ...

  10. 通过命令行给 XenServer 打补丁

    安装 XenCenter 客户端,cmd 到 XenCenter 安装目录. 1.上传补丁到服务器,获得uuid xe patch-upload -s <服务器IP地址> -u root ...