JAVA多线程基础篇--守护线程(Daemon Thread)
1.概述
JAVA中的线程主要分为两类:用户线程(User Thread)和守护线程(Daemon Thread)。JAVA语言中无论是线程还是线程池,默认都是用户线程,因此用户线程也被称为普通线程。守护线程也被称之为后台线程、服务线程或精灵线程,守护线程是为用户线程服务的,当线程中的用户线程都执行结束后,守护线程也会跟随结束。守护线程具有自动结束生命周期的特性,而非守护线程则不具备该特性。本文将编写一些案例,同时根据源码来对用户线程和守护线程进行分析,帮助大家更好地理解。
2.守护线程分析
2.1 案例分析
上面讲了这么多概念,不如直接上一段代码来看一下:
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.TimeUnit;@Slf4j
public class DaemonThreadDemo {public static void main(String[] args) {log.info("当前线程:{}", Thread.currentThread().getName());//创建一个用户线程,一直运行Thread thread = new Thread(() -> {while (true) {try {TimeUnit.SECONDS.sleep(1);log.info("当前线程:【{}】,正在运行", Thread.currentThread().getName());} catch (InterruptedException e) {log.error("当前线程:{},休眠异常:{}", Thread.currentThread().getName(), e);}}}, "子线程");//启动线程thread.start();//主线程休眠2stry {TimeUnit.SECONDS.sleep(2);log.info("主线程:{},休眠2s", Thread.currentThread().getName());} catch (InterruptedException e) {log.error("主线程:{}休眠异常:{}", Thread.currentThread().getName(), e);}//主线程结束,打印信息log.info("主线程:{},结束运行", Thread.currentThread().getName());}
}
上述代码的主要运行流程如下图所示:
主线程main线程启动后,首先会去创建一个用户线程(该用户线程内部是一个死循环,会一直运行),接下来会启动该用户线程,最后主线程休眠并退出。上述代码中,线程启动后,当主线程运行结束后,JVM也不会退出,因为名称为子线程的用户线程还在后台运行,而且如无异常中断会一直运行。运行结果截图如下所示:
如果修改上述代码为守护线程呢?运行结果又会怎样?对上述代码做如下修改:
//新增监听JVM是否退出的Hook线程,Hook线程能够在JVM程序退出的时候被启动执行Runtime.getRuntime().addShutdownHook(new Thread(() -> {log.info("JVM运行结束......");}));//将线程设置为守护线程thread.setDaemon(true);
修改代码后,运行结果如下图所示:
由上述运行结果可知,当主线运行结束后,JVM也结束了运行,被设置为守护线程的子线程也结束了运行。
2.2 代码分析
2.2.1 设置线程为守护线程
线程可以通过 setDaemon(true) 方法将线程类型更改为守护线程,主要代码如下所示:
Thread thread = new Thread(()-> {@Overridepublic void run() {System.out.println("我是子线程");}});
//将线程设置为守护线程thread.setDaemon(true);
2.2.2 判断是否为守护线程
线程可以通过isDaemon()方法来判断当前线程或指定线程是否为守护线程,如果是守护线程则结果为true,否则为false。具体代码如下:
import lombok.extern.slf4j.Slf4j;@Slf4j
public class IsDaemonThread {public static void main(String[] args) {Runtime.getRuntime().addShutdownHook(new Thread(() -> {log.info("JVM运行结束......");}));Thread thread = new Thread(() -> {log.info("线程:{},是否是守护线程:{}", Thread.currentThread().getName(), Thread.currentThread().isDaemon());}, "子线程");thread.setDaemon(true);thread.start();log.info("主线程:{},IsDaemon:{}", Thread.currentThread().getName(), Thread.currentThread().isDaemon());}
}
运行结果为:
2.2.3 判断守护线程的优先级
运行结果如下图所示:
由上述运行结果可知,守护线程和用户线程是同一个优先级。我看部分文章或博客写的是用户线程优先级大于守护线程,如果有详细证明过程,可以推荐给我。
2.2.4 设置线程池为守护线程
如果设置线程池为守护线程,则需要将线程池中每个线程都设置为守护线程,具体代码如下:
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;public class ThreadPoolDaemonDemo {public static void main(String[] args) {ExecutorService threadPool = Executors.newFixedThreadPool(10, new ThreadFactory() {@Overridepublic Thread newThread(Runnable r) {Thread t = new Thread(r);// 设置线程为守护线程t.setDaemon(true);return t;}});System.out.println("线程池创建成功!");Thread thread1 = new Thread(() -> {System.out.println("hello ThreadPoolDaemonDemo1");});threadPool.submit(thread1);Set<Thread> threadSet = Thread.getAllStackTraces().keySet();for (Thread thread : threadSet) {System.out.println("thread.name=【" + thread.getName() + "】;group=" + thread.getThreadGroup() + ";isDaemon=" + thread.isDaemon() + ";priority=" + thread.getPriority());}}
}
线程运行结果为:
由上述结果看出,当将线程池设置为守护线程时,其内部线程都是守护线程;为了验证上述猜想,我编写了一个循环,测试了提交不同数量的线程任务,来查看该线程是否属于守护线程,结果表明均为守护线程。修改代码如下:
for (int i = 0; i < 10; i++) {threadPool.submit(thread1);}
结果为:
2.2.5 判断守护线程子线程是否守护
下面编写一段测试代码,来判断守护线程创建的线程是否为守护线程,具体如下:
上述代码的运行结果如下:
由上述运行结果可知:守护线程中创建的子线程,默认情况下也属于守护线程。
2.3 注意事项
1. setDaemon(true) 必须写在start方法前面;
setDaemon(true) 如果设置在 start() 之后,不但程序的执行会报错,而且设置的守护线程也不会生效。具体效果如下所示:
@Slf4j
public class DaemonThreadDemo {public static void main(String[] args) {Runtime.getRuntime().addShutdownHook(new Thread(() -> {log.info("JVM运行结束......");}));Thread thread = new Thread(() -> {while (true) {try {TimeUnit.SECONDS.sleep(1);log.info("当前线程:【{}】,正在运行", Thread.currentThread().getName());log.info("当前线程:【{}】,优先级为:{}", Thread.currentThread().getName(), Thread.currentThread().getPriority());} catch (InterruptedException e) {log.error("当前线程:{},休眠异常:{}", Thread.currentThread().getName(), e);}}}, "子线程");thread.start();//设置守护线程thread.setDaemon(true);try {TimeUnit.SECONDS.sleep(2);log.info("主线程:{},休眠2s", Thread.currentThread().getName());} catch (InterruptedException e) {log.error("主线程:{}休眠异常:{}", Thread.currentThread().getName(), e);}log.info("当前线程:【{}】,优先级为:{}", Thread.currentThread().getName(), Thread.currentThread().getPriority());log.info("主线程:{},结束运行", Thread.currentThread().getName());}
}
2.不能把正在运行中的线程设置为守护线程;
3.复杂计算、资源回收这种,不适合使用守护线程来执行。
3.小结
1.守护线程是用来为用户线程服务的,当一个程序中的所有用户线程都结束之后,无论守护线程是否在工作都会跟随用户线程一起结束;
2.守护线程的子线程也是守护线程;
3.守护线程的优先级和用户线程优先级一致;
4.守护线程setDaemon(true) 如果设置在 start() 之后,程序执行会报错,守护线程也不会生效。
4.应用场景
1.垃圾回收线程就是典型的守护线程,随主线程结束而结束;
2.应用指标统计,部分服务可以通过守护线程来采取应用指标,服务结束则停止采集。
5.参考文献
1.https://www.jianshu.com/p/a157d749b5e8
2.https://www.cnblogs.com/quanxiaoha/p/10731361.html
3.https://juejin.cn/post/7006879369368961061
4.《JAVA多线程编程核心技术》-高洪岩著
相关文章:

JAVA多线程基础篇--守护线程(Daemon Thread)
1.概述 JAVA中的线程主要分为两类:用户线程(User Thread)和守护线程(Daemon Thread)。JAVA语言中无论是线程还是线程池,默认都是用户线程,因此用户线程也被称为普通线程。守护线程也被称之为后台线程、服务线程或精灵…...

对知识蒸馏的一些理解
知识蒸馏是一种模型压缩技术,它通过从一个大模型(教师模型)中传输知识到一个小模型(学生模型)中来提高学生模型的性能,知识蒸馏也要用到真实的数据集标签。 软损失soft loss就是拿教师模型在蒸馏温度为T的…...

概率论_概率公式中的分号(;)、逗号(,)、竖线(|) 及其优先级
目录 1.概率公式中的分号(;)、逗号(,)、竖线(|) 2.各种概率相关的基本概念 2.1 联合概率 2.2 条件概率(定义) 2.3 全概率(乘法公式的加强版) 2.4 贝叶斯公式 贝叶斯定理的公式推导 1.概率公式中的分号(;)、逗号(,)、竖线(|) ; 分号代表前后是两类…...

【C++】二叉树进阶 -- 详解
一、二叉搜索树概念 二叉搜索树 又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树: 若它的左子树不为空,则左子树上所有节点的值都小于根节点的值 若它的右子树不为空,则右子树上所有节点的值都大于根节点…...
K8S集群中Node节点资源不足导致Pod无法运行的故障排查思路
K8S集群中Node节点资源不足导致Pod无法运行的故障排查思路 Node节点资源不足可能会产生的故障 故障一:Pod数量太多超出物理节点的限制每一台Node节点中默认限制最多运行110个Pod资源,当一个应用程序有成百上千的Pod资源时,如果不扩容Node节…...
Node.js与npm版本比对
Node.js与npm版本比对 Node.js与npm版本比对版本对比表Node版本对比 Node.js与npm版本比对 我们在项目开发过程中,经常会遇到公司一些老的前端工程项目,而我们当前的node及npm版本都是相对比较新的了。 在运行以前工程时,会遇到相关环境不匹…...

智加科技与东风柳汽达成深度合作 自动驾驶重卡计划2024年初量产交付
(2023年10月19日,苏州)全球领先的重卡自动驾驶技术公司智加科技与东风柳汽宣布,双方共同开发的自动驾驶重卡H7计划2024年初实现量产交付。未来,双方将携手推出安全可靠、高性价比、性能卓越的自动驾驶重卡产品…...
mac下配置环境-node以及nvm
当前配置环境主要针对于mac下系统,需要提前安装brew包 如需要配置,可查阅:Brew包的基本安装(手把手教学)-CSDN博客 如果是window环境配置,分享一个不错的帖子:nvm的安装和使用(详细&…...
Elasticsearch基础篇(六):es创建映射和设置
es创建映射和设置 一、什么是 Elasticsearch 映射?二、映射中的字段类型常见字段类型 (Common data types)对象和关联类型(Objects and relational types)结构化数据类型(Structured data types)…...

机器人系统 ROS 常用命令行工具
1. 启动ros 主节点 roscore roscore运行成功如图: 1.1 rosrun 启动服务节点 例子:启动一个小乌龟节点 rosrun turtlesim turtlesim_node运行结果如图: 1.2 启动键盘控制 打开新的命令窗口,启动turtle_teleop_key 节点 rosr…...
Jasypt加解密、信息脱敏
文章目录 一、介绍二、Spring集成1、 Maven依赖2、application.xml的配置3、配置文件使用4、方法加密 二、SpringBoot集成1、 Maven依赖2、 Java Bean配置jasyptStringEncryptor3、配置文件使用4、Bean使用加密字段自动解密 一、介绍 Jasypt is a java library which allows th…...

力扣每日一题61:旋转链表
题目描述: 给你一个链表的头节点 head ,旋转链表,将链表每个节点向右移动 k 个位置。 示例 1: 输入:head [1,2,3,4,5], k 2 输出:[4,5,1,2,3]示例 2: 输入:head [0,1,2], k 4 输…...

SSM - Springboot - MyBatis-Plus 全栈体系(三十六)
第八章 项目实战 四、后台功能开发 3. 头条模块开发 3.1 登陆验证和保护 3.1.1 需求描述 客户端在进入发布页前、发布新闻前、进入修改页前、修改前、删除新闻前先向服务端发送请求携带 token 请求头后端接收 token 请求头后,校验用户登录是否过期并做响应前端根…...

作为开发的我能力模型图是什么样子的,应该如何去绘制?
作为开发的我能力模型图是什么样子的,应该如何去绘制? 能力模型图是一种用来描述个人或职位所需技能和能力的工具,对于开发人员来说,能力模型图通常包括技术能力、软技能和专业知识等多个维度。下面是一种可能的构建和绘制开发人员…...

【会议征稿通知】第三届密码学、网络安全和通信技术国际会议(CNSCT 2024)
第三届密码学、网络安全和通信技术国际会议(CNSCT 2024) 2024 3rd International Conference on Cryptography, Network Security and Communication Technology 随着互联网和网络应用的不断发展,网络安全在计算机科学中的地位越来越重要&…...

Python学习笔记——MYSQL,SQL核心
食用说明:本笔记适用于有一定编程基础的伙伴们。希望有助于各位! SQL语言分类 SQL注释 库管理 表管理 数据操作 分组聚合 分页限制 需要注意的是关键字的顺序不可以错乱,否则会报错其中LIMIT关键字的n是指从第n个开始,m是指查…...

集成学习方法之随机森林-入门
1、 什么是集成学习方法 集成学习通过建立几个模型组合的来解决单一预测问题。它的工作原理是生成多个分类器/模型,各自独立地学习和作出预测。这些预测最后结合成组合预测,因此优于任何一个单分类的做出预测。 2、 什么是随机森林 在机器学习中&…...

blender怎么在一个面上对半切割(不影响别的面)
1进入编辑模式 2.在面选择模式下,选中该物体需要切割成两半的面。 3.按K这个快捷键(切记,必须得用快捷键,不用的话没办法调出第一个绿色切割点),将切割点移动到需要切割的起始边,按住Shift键不放…...

vue3中使用vue3-pdf-app和使用浏览器内置的PDF插件浏览器PDF文件
文章目录 先准备一个PDF使用浏览器内置的PDF插件预览PDF在HTML中使用浏览器插件预览PDFVscode使用插件发布服务后直接通过URL地址访问PDF可使用的浏览器 在vue3项目中预览PDF文件vue3项目也是可以通过URL地址访问文件的vue3中使用浏览器内置的PDF插件预览PDF代码如下所示&#…...
fastadmin 后台添加视频
做个记录,字段自行对照解决 1.add.html <div class"form-group"><label class"control-label col-xs-12 col-sm-2">{:__(Video)}:</label><div class"col-xs-12 col-sm-8"><div class"input-group">&l…...
三维GIS开发cesium智慧地铁教程(5)Cesium相机控制
一、环境搭建 <script src"../cesium1.99/Build/Cesium/Cesium.js"></script> <link rel"stylesheet" href"../cesium1.99/Build/Cesium/Widgets/widgets.css"> 关键配置点: 路径验证:确保相对路径.…...
Java如何权衡是使用无序的数组还是有序的数组
在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...

uniapp微信小程序视频实时流+pc端预览方案
方案类型技术实现是否免费优点缺点适用场景延迟范围开发复杂度WebSocket图片帧定时拍照Base64传输✅ 完全免费无需服务器 纯前端实现高延迟高流量 帧率极低个人demo测试 超低频监控500ms-2s⭐⭐RTMP推流TRTC/即构SDK推流❌ 付费方案 (部分有免费额度&#x…...
大模型多显卡多服务器并行计算方法与实践指南
一、分布式训练概述 大规模语言模型的训练通常需要分布式计算技术,以解决单机资源不足的问题。分布式训练主要分为两种模式: 数据并行:将数据分片到不同设备,每个设备拥有完整的模型副本 模型并行:将模型分割到不同设备,每个设备处理部分模型计算 现代大模型训练通常结合…...
基于matlab策略迭代和值迭代法的动态规划
经典的基于策略迭代和值迭代法的动态规划matlab代码,实现机器人的最优运输 Dynamic-Programming-master/Environment.pdf , 104724 Dynamic-Programming-master/README.md , 506 Dynamic-Programming-master/generalizedPolicyIteration.m , 1970 Dynamic-Programm…...
rnn判断string中第一次出现a的下标
# coding:utf8 import torch import torch.nn as nn import numpy as np import random import json""" 基于pytorch的网络编写 实现一个RNN网络完成多分类任务 判断字符 a 第一次出现在字符串中的位置 """class TorchModel(nn.Module):def __in…...

C# 表达式和运算符(求值顺序)
求值顺序 表达式可以由许多嵌套的子表达式构成。子表达式的求值顺序可以使表达式的最终值发生 变化。 例如,已知表达式3*52,依照子表达式的求值顺序,有两种可能的结果,如图9-3所示。 如果乘法先执行,结果是17。如果5…...

【p2p、分布式,区块链笔记 MESH】Bluetooth蓝牙通信 BLE Mesh协议的拓扑结构 定向转发机制
目录 节点的功能承载层(GATT/Adv)局限性: 拓扑关系定向转发机制定向转发意义 CG 节点的功能 节点的功能由节点支持的特性和功能决定。所有节点都能够发送和接收网格消息。节点还可以选择支持一个或多个附加功能,如 Configuration …...
Kubernetes 网络模型深度解析:Pod IP 与 Service 的负载均衡机制,Service到底是什么?
Pod IP 的本质与特性 Pod IP 的定位 纯端点地址:Pod IP 是分配给 Pod 网络命名空间的真实 IP 地址(如 10.244.1.2)无特殊名称:在 Kubernetes 中,它通常被称为 “Pod IP” 或 “容器 IP”生命周期:与 Pod …...

小智AI+MCP
什么是小智AI和MCP 如果还不清楚的先看往期文章 手搓小智AI聊天机器人 MCP 深度解析:AI 的USB接口 如何使用小智MCP 1.刷支持mcp的小智固件 2.下载官方MCP的示例代码 Github:https://github.com/78/mcp-calculator 安这个步骤执行 其中MCP_ENDPOI…...