守护线程和非守护线程

news2024/9/30 17:35:30

一、前言

借鉴文章

文章1
文章2

①Java提供的两种线程

Java提供了两种线程: 守护线程和用户线程(非守护线程)

守护线程(Daemon Thread): 在程序运行时 在后台提供一种通用服务的线程,这种线程并不属于程序中不可或缺的部分。任何一个守护线程都是整个JVM中所有非守护线程的“保姆”。

  • 守护线程是一种在后台提供服务的线程,它的存在并不会阻止Java虚拟机(JVM)的退出。

  • 当所有的非守护线程执行完毕或者终止时,JVM会检查是否还有任何活动的守护线程。如果只剩下守护线程,JVM会优雅地关闭守护线程并退出。

  • 可以通过调用Thread类的setDaemon(true)方法将线程设置为守护线程。

用户线程(非守护线程,Non-daemon Thread): 用户线程基本上和守护线程一样,唯一的不同之处在于如果用户线程全部退出运行,只剩下守护线程存在了,JVM就会退出。因为当所有非守护线程结束时,没有了被守护者,守护线程也就没有工作可做,当然也就没有继续执行的必要了,程序就会终止,同时会杀死所有的"守护线程",也就是说只要有任何非守护线程还在运行,程序就不会终止

  • 非守护线程是一种正常的线程,它的存在会阻止JVM的退出,直到所有的非守护线程执行完毕或者手动调用System.exit()方法退出程序。
  • 默认情况下,通过Thread类创建的线程都是非守护线程。

②JVM正常情况的退出

JDK官方文档:

The Java Virtual Machine exits when the only threads running are all daemon threads.

当 JVM 中不存在任何一个正在运行的非守护线程时,则 JVM 进程即会退出。

③守护线程应用场景(作用)

当JVM中没有一个正在运行的非守护线程,这个时候JVM就会退出,也就是说守护线程拥有自动结束自己声明周期的特性,而非守护线程不具备这个特点JVM中的垃圾回收线程就是典型的守护进程,当非守护线程都没有了,那要垃圾回收线程干什么,直接结束JVM即可。守护线程一般用于执行一些后台任务,在程序或JVM退出时候,守护线程能够自动关闭,具体场景如下:

  1. 后台任务处理:守护线程通常用于执行一些后台任务,这些任务对于整个程序的运行并不是必需的,而且在程序的主要逻辑结束时可以被安全地终止。例如,日志记录、性能统计、定时任务等可以作为守护线程来执行。
  2. 服务监控和管理:守护线程常常被用来监控和管理其他线程或资源,确保它们的正常运行。例如,在服务器应用中,可以使用守护线程来监控网络连接、数据库连接等资源,及时释放无用资源或重新尝试连接。
  3. 辅助性工作:一些辅助性的工作可以交给守护线程来完成,比如周期性的数据清理、定时任务的执行等。
  4. 资源回收:守护线程通常用于执行垃圾回收(Garbage Collection)工作,确保程序的内存得到及时的回收和释放,以避免内存泄漏问题。

④Hook线程(下面会用到)

Hook线程概念:

Hook线程即钩子(Hook)线程,在程序即将退出,即JVM程序即将退出的时候,Hook线程会被启动执行。

Hook线程代码示例:

package com;

import java.util.concurrent.TimeUnit;

/**
 * @author banana
 * @create 2023-11-07 16:27
 */
public class HookTask {
    public static void main(String[] args) {
        //为应用程序注入Hook(钩子)线程
        Runtime.getRuntime().addShutdownHook(new Thread(() ->{
            System.out.println("the hook thread 1 is running.");
            try {
                //休眠2秒
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("the hook thread 1 will exit");
        }));
        
        System.out.println("the main thread will exit.");
    }
}

运行结果:

可以看出,当主线程结束的,也就是JVM进程即将退出的时候,注入的Hook线程启动并打印相关日志。

在这里插入图片描述

注意事项:

  1. Hook 线程只有在正确接收到退出信号时,才能被正确执行,如果你是通过 kill -9这种方式,强制杀死的进程,那么抱歉,进程是不会去执行 Hook 线程的,为什么呢?你想啊,它自己都被强制干掉了,哪里还管的上别人呢?
  2. 请不要在 Hook 线程中执行一些耗时的操作,这样会导致程序长时间不能退出。

二、守护线程实例

①非守护线程不退出情况

代码:

public class SHOUHUXCTS {

    public static void main(String[] args) {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                while(true){
                    //睡眠一会
                    try {
                        TimeUnit.SECONDS.sleep(1);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("当前线程:" + Thread.currentThread().getName());
                }
            }
        });

        //启动用户线程(这里是非守护线程)
        thread.start();
        //主线程退出
        System.out.println("The main thread ready to exit…");
    }
}

运行结果:

可以看到,主线程main thread已经结束了,但是我们自定义的线程(非守护线程)是会持续运行的,即JVM进程依赖没有退出,当前非守护线程仍旧在运行中。

在这里插入图片描述

②守护线程退出情况

代码:

package com.yjy;

import java.util.concurrent.TimeUnit;

/**
 * @author banana
 * @create 2023-11-07 15:44
 */
public class SHOUHUXCTS {

    public static void main(String[] args) {
        //设置一个钩子线程,在JVM退出时输出日志
        Runtime.getRuntime()
                .addShutdownHook(new Thread(() -> System.out.println("The JVM exit success")));


        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                while(true){
                    //睡眠一会
                    try {
                        TimeUnit.SECONDS.sleep(1);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("当前线程:" + Thread.currentThread().getName());
                }
            }
        });

        //设置当前线程为守护线程
        thread.setDaemon(true);

        //启动用户线程(这里是非守护线程)
        thread.start();

        //主线程退出
        System.out.println("The main thread ready to exit…");
    }
}

运行结果:

可以看到当主线程退出时,JVM会随之退出运行,守护线程也同时会被回收。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1180880.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何使用 NFTScan NFT API 在 Arbitrum 网络上开发 Web3 应用

Arbitrum 是以太坊的 Layer 2 扩容方案,为以太坊面临的高 gas 费和网络拥堵问题,提供了一个解决方案。作为 Layer 1 的以太坊基础层受每秒只能验算 15 笔交易的限制,在目前以太坊使用需求庞大的情况下,局限了以太坊的可扩展性。Ar…

计算机毕业设计 基于SpringBoot房屋租赁管理系统的设计与实现 Javaweb项目 Java实战项目 前后端分离 文档报告 代码讲解 安装调试

🍊作者:计算机编程-吉哥 🍊简介:专业从事JavaWeb程序开发,微信小程序开发,定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事,生活就是快乐的。 🍊心愿:点…

机器视觉 opencv 深度学习 驾驶人脸疲劳检测系统 -python 计算机竞赛

文章目录 0 前言1 课题背景2 Dlib人脸识别2.1 简介2.2 Dlib优点2.3 相关代码2.4 人脸数据库2.5 人脸录入加识别效果 3 疲劳检测算法3.1 眼睛检测算法3.2 打哈欠检测算法3.3 点头检测算法 4 PyQt54.1 简介4.2相关界面代码 5 最后 0 前言 🔥 优质竞赛项目系列&#x…

深度学习经典网络:GoogleNet

深度学习经典网络--GoogleNet 1、为什么要提出Inception2、为什么是Inception3、实际中的Inception4、GoogleNet 整体网络结构 GoogLeNet是google推出的基于Inception模块的深度神经网络模型,在2014年的ImageNet竞赛中夺得了冠军,在随后的两年中一直在改…

全方位解析解决找不到msvcp120dll,无法继续执行代码问题的方法

在日常使用电脑的过程中,我们可能会遇到 “找不到msvcp120dll,无法继续执行代码” 的问题。大部分用户并不清楚msvcp120.dll是什么,更不知道怎样修复这个问题。其实不要紧的,今天我们就来了解一下msvcp120.dll文件,并且告知你多种…

react antd message多条数据展示样式

最终效果: 前言: 平时我们经常用到message来做一些错误提示,最常见的就是单行提示。如下图: 实现代码: message.error(This is an error message)多行动态message实现 参考文献:antd message 链接地址&a…

SOLIDWORKS 2024新产品发布会暨SOLIDWORKS 创新日活动-硕迪科技

“达索系统SOLIDWORKS 2024新产品发布会暨SOLIDWORKS创新日” 线下发布会即将登场!硕迪科技与达索系统携手为您奉上一场“云享未来,智协未来”的创新年度盛会,欢迎莅临! SOLIDWORKS 2024 以更加强大的姿态亮相,帮助您…

Python小技巧:bytes与str的区别

嗨喽~大家好呀,这里是魔王呐 ❤ ~! python更多源码/资料/解答/教程等 点击此处跳转文末名片免费获取 bytes实例包含的是原始数据,即8位的无符号值(通常按照ASCII编码标准来显示)。 a bh\x65llo print(list(a)) print(a) >>> [104, 101, …

【1107】有关环境的学习记录。。。

有关python环境!!! 1、python解释器就是 python 3.7.2 之类的。 VSCode 是代码编辑器。 下图的每一个都是可选的python环境,Python 3.8.3(‘base’)是下载在电脑上的python环境(下载miniConda时…

深入解析 Redis 分布式锁原理

一、实现原理 1.1 基本原理 JDK 原生的锁可以让不同线程之间以互斥的方式来访问共享资源,但如果想要在不同进程之间以互斥的方式来访问共享资源,JDK 原生的锁就无能为力了。此时可以使用 Redis 来实现分布式锁。 Redis 实现分布式锁的核心命令如下&am…

chrome v3开发插件实现所有网站允许跨域

场景: chrome 插件 升级到v3后,原来修改请求响应都变成异步,即无法同步拦截来修改请求响应。 在v3中也不支持修改请求响应内容。 问题:如何在chrome v3中允许其他网站跨域呢。 方式一:禁用chrome跨域,禁…

JPA编程中自定义SQL语句使用case/when语句实现分页查询和分类排序的示例

一、需求背景 查询我发起的以及被邀请的工单列表,要求分页查询,排序的具体要求是: 先按状态排序,未处理的排前面再按处理人排序,被邀请的排前面,自己发起的排后面最后按修改时间倒序 处理状态包括三种&a…

云尘靶场-Tr0ll-vulhub

直接fscan扫描 发现这里有一个ftp 我们等等看 首先去nmap扫描端口 nmap -A -p- 172.25.0.13 --unprivileged 这里使用wsl ftp ssh 和80 然后我们继续继续目录扫描 dirb 出来没什么用处 所以我们继续去看 流量包 流量包分析 首先看tcp ->分析->追踪流 这里是f…

什么是Kubernetes RBAC?为什么需要它?

目录 什么是Kubernetes RBAC? 如何启用Kubernetes RBAC 1.服务帐户 2.角色和集群角色 3.角色绑定和集群角色绑定 Kubernetes RBAC的好处 1.适当的授权 2.职责分离 3.100%遵守法规 Kubernetes RBAC的缺点 企业软件开发工具 什么是Kubernetes RBAC? 当组织开始走上…

英国最值得参观的十大博物馆介绍

目前,到英国从事访问交流及博士后研究的学者越来越多,而英国一向以厚重的历史人文以及精彩绝伦的艺术著称,在这样一个有着浓厚历史沉淀的国家,自然最不缺的就是博物馆了,在学习工作的闲暇,可以去参观体验一…

C语言求解有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,问每个月的兔子总数为多少?

完整代码: /*有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第三个月后每个月 又生一对兔子,假如兔子都不死,问每个月的兔子总数为多少? 程序分析: 兔子的规律为数列1,1,2,3,5,8…

AI智能公文写作助手“文山会海“

公文写作痛点 没思路,公文写作无从下手公文类型繁多,一时难以全面掌握公文内容组织难度大,不易清晰、有逻辑的进行表达时间紧任务急,往往需要在有限的时间内完成大量写作工作反复修改优化,需满足更多新要求&#xff0…

WordPress 企业一号wp主题企业建站模板V1.2.2开心版

模板简介: 企业一号是一款由主题巴巴团队原创设计开发的WordPress企业主题。这款主题配备了强大的可视化、模块化的页面设计功能(页面构建器),让您通过添加不同的设计模块和配置模块选项就可以设计出各种丰富多彩的页面。主题还集…

信号发送与处理-上

问题 按下 Ctrl C 后,命令行中的前台进程会被终止。为什么??? 什么是信号? 信号是一种 "软件中断",用来处理异步事件 内核发送信号到某个进程,通知进程事件的发送事件可能来自硬件…

③【操作表数据】MySQL添加数据、修改数据、删除数据

个人简介:Java领域新星创作者;阿里云技术博主、星级博主、专家博主;正在Java学习的路上摸爬滚打,记录学习的过程~ 个人主页:.29.的博客 学习社区:进去逛一逛~ MySQL添加数据、修改数据、删除数据 &#x1f…