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

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

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

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

package com.itsoku.chat03;

/**
* 微信公众号:路人甲Java,专注于java技术分享(带你玩转 爬虫、分布式事务、异步消息服务、任务调度、分库分表、大数据等),喜欢请关注!
*/
public class Demo1 { public static class T1 extends Thread {
public T1(String name) {
super(name);
} @Override
public void run() {
System.out.println(this.getName() + "开始执行," + (this.isDaemon() ? "我是守护线程" : "我是用户线程"));
while (true) ;
}
} public static void main(String[] args) {
T1 t1 = new T1("子线程1");
t1.start();
System.out.println("主线程结束");
}
}

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

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

再看下面的代码:

package com.itsoku.chat03;

/**
* 微信公众号:路人甲Java,专注于java技术分享(带你玩转 爬虫、分布式事务、异步消息服务、任务调度、分库分表、大数据等),喜欢请关注!
*/
public class Demo2 { public static class T1 extends Thread {
public T1(String name) {
super(name);
} @Override
public void run() {
System.out.println(this.getName() + "开始执行," + (this.isDaemon() ? "我是守护线程" : "我是用户线程"));
while (true) ;
}
} public static void main(String[] args) {
T1 t1 = new T1("子线程1");
t1.setDaemon(true);
t1.start();
System.out.println("主线程结束");
}
}

运行结果:

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

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

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

package com.itsoku.chat03;

import java.util.concurrent.TimeUnit;

/**
* 微信公众号:路人甲Java,专注于java技术分享(带你玩转 爬虫、分布式事务、异步消息服务、任务调度、分库分表、大数据等),喜欢请关注!
*/
public class Demo3 { public static void main(String[] args) {
Thread t1 = new Thread() {
@Override
public void run() {
try {
TimeUnit.SECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
t1.start();
t1.setDaemon(true);
}
}

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

线程daemon的默认值

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

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

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

示例代码:

package com.itsoku.chat03;

import java.util.concurrent.TimeUnit;

/**
* 微信公众号:路人甲Java,专注于java技术分享(带你玩转 爬虫、分布式事务、异步消息服务、任务调度、分库分表、大数据等),喜欢请关注!
*/
public class Demo4 {
public static class T1 extends Thread {
public T1(String name) {
super(name);
} @Override
public void run() {
System.out.println(this.getName() + ".daemon:" + this.isDaemon());
}
} public static void main(String[] args) throws InterruptedException { System.out.println(Thread.currentThread().getName() + ".daemon:" + Thread.currentThread().isDaemon()); T1 t1 = new T1("t1");
t1.start(); Thread t2 = new Thread() {
@Override
public void run() {
System.out.println(this.getName() + ".daemon:" + this.isDaemon());
T1 t3 = new T1("t3");
t3.start();
}
}; t2.setName("t2");
t2.setDaemon(true);
t2.start(); TimeUnit.SECONDS.sleep(2);
}
}

运行代码,输出:

main.daemon:false
t1.daemon:false
t2.daemon:true
t3.daemon:true

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

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

总结

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

java高并发系列

java高并发系列连载中,总计估计会有四五十篇文章,可以关注公众号:javacode2018,获取最新文章。

java高并发系列交流群

java高并发系列 - 第9天:用户线程和守护线程的更多相关文章

  1. java高并发系列 - 第5天:深入理解进程和线程

    进程 进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础.程序是指令.数据及其组织形式的描述,进程是程序的实体. 进程具有的 ...

  2. java高并发系列-第1天:必须知道的几个概念

    java高并发系列-第1天:必须知道的几个概念 同步(Synchronous)和异步(Asynchronous) 同步和异步通常来形容一次方法调用,同步方法调用一旦开始,调用者必须等到方法调用返回后, ...

  3. java高并发系列 - 第6天:线程的基本操作

    新建线程 新建线程很简单.只需要使用new关键字创建一个线程对象,然后调用它的start()启动线程即可. Thread thread1 = new Thread1(); t1.start(); 那么 ...

  4. java高并发系列 - 第12天JUC:ReentrantLock重入锁

    java高并发系列 - 第12天JUC:ReentrantLock重入锁 本篇文章开始将juc中常用的一些类,估计会有十来篇. synchronized的局限性 synchronized是java内置 ...

  5. java高并发系列 - 第14天:JUC中的LockSupport工具类,必备技能

    这是java高并发系列第14篇文章. 本文主要内容: 讲解3种让线程等待和唤醒的方法,每种方法配合具体的示例 介绍LockSupport主要用法 对比3种方式,了解他们之间的区别 LockSuppor ...

  6. java高并发系列 - 第15天:JUC中的Semaphore,最简单的限流工具类,必备技能

    这是java高并发系列第15篇文章 Semaphore(信号量)为多线程协作提供了更为强大的控制方法,前面的文章中我们学了synchronized和重入锁ReentrantLock,这2种锁一次都只能 ...

  7. java高并发系列 - 第16天:JUC中等待多线程完成的工具类CountDownLatch,必备技能

    这是java高并发系列第16篇文章. 本篇内容 介绍CountDownLatch及使用场景 提供几个示例介绍CountDownLatch的使用 手写一个并行处理任务的工具类 假如有这样一个需求,当我们 ...

  8. java高并发系列 - 第17天:JUC中的循环栅栏CyclicBarrier常见的6种使用场景及代码示例

    这是java高并发系列第17篇. 本文主要内容: 介绍CyclicBarrier 6个示例介绍CyclicBarrier的使用 对比CyclicBarrier和CountDownLatch Cycli ...

  9. java高并发系列 - 第21天:java中的CAS操作,java并发的基石

    这是java高并发系列第21篇文章. 本文主要内容 从网站计数器实现中一步步引出CAS操作 介绍java中的CAS及CAS可能存在的问题 悲观锁和乐观锁的一些介绍及数据库乐观锁的一个常见示例 使用ja ...

随机推荐

  1. Goland安装

    Goland安装 http://c.biancheng.net/view/6124.html

  2. Pipe——高性能IO(二)

    Pipelines - .NET中的新IO API指引(一) Pipelines - .NET中的新IO API指引(二) 关于System.IO.Pipelines的一篇说明 System.IO.P ...

  3. 从壹开始[做贡献]之二 || 推荐VSCode多语言开发,支持一键JAVA

    缘起 哈喽大家周一好!好久不见鸭,最近在看一本书,很好,<人类简史>,适合夏日星空,仰观宇宙之大

  4. 线段树模板加模板题POJ3468

    POJ - 3468 整理了个新的线段树的模板,暑期集训的时候学长给的模板,每个节点单单存了自己所要维护的内容,还是少了点.导致在写pushdown的时候,len我会有点难写.所以就整理个新的模板. ...

  5. IT兄弟连 HTML5教程 HTML5文字版面和编辑标签 使用HTML表格

    表格在网站中应用得非常广泛,使用它可以方便.灵活地排版,很多动态大型网站也都是借助表格排版的,但现在都使用DIV+CSS进行页面布局.表格可以把相互关联的信息元素集中定位,使浏览页面的人一目了然.在H ...

  6. 痞子衡嵌入式:飞思卡尔i.MX RTyyyy系列MCU特性那些事(2)- RT1052DVL6性能实测(CoreMark)

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是飞思卡尔i.MX RTyyyy系列MCU的性能. 在前面的文章 i.MXRTyyyy微控制器概览 里,痞子衡给大家简介过恩智浦半导体在2 ...

  7. java高并发系列 - 第26篇:学会使用JUC中常见的集合,常看看!

    这是java高并发系列第26篇文章. 环境:jdk1.8. 本文内容 了解JUC常见集合,学会使用 ConcurrentHashMap ConcurrentSkipListMap Concurrent ...

  8. C# params 用法

    params 主要用在方法或函数参数数组中, 1,当参数个数不确定时使用 2,不能盒ref,和out组合使用 3,与参数数组对应的实参可以时一个 同类型数组,也可以时任意多个同类型变量 4,实参是数组 ...

  9. JavaWeb入门——背景知识

    JavaWeb入门——背景知识 摘要:本文主要介绍了Web服务器的相关知识. 概念 什么是JavaWeb JavaWeb,是用Java技术来解决相关Web互联网领域的技术的总称.Web包括:Web服务 ...

  10. 大数据相关概念和hdfs

    大数据 概述 大数据是新处理模式才能具备更多的决策力,洞察力,流程优化能力,来适应海量高增长率,多样化的数据资产. 大数据面临的问题 怎么存储海量数据(kb,mb,gb,tb,pb,eb,zb) 怎么 ...