Java守护线程的理解及应用

news2024/11/26 16:55:57

在Java中有两类线程,分别是User Thread(用户线程)和Daemon Thread(守护线程) 。
用户线程很好理解,我们日常开发中编写的业务逻辑代码,运行起来都是一个个用户线程。而守护线程相对来说则要特别理解一下。

1.1 什么是守护线程

在操作系统里面是没有所谓的守护线程的概念的,只有守护进程一说。但是Java语言机制是构建在JVM的基础之上的,这一机制意味着Java平台是把操作系统的底层给屏蔽了起来,所以它可以在它自己的虚拟的平台里面构造出对自己有利的机制。而Java语言或者说平台的设计者多多少少是收到Unix操作系统思想的影响,而守护线程机制又是对JVM这样的平台凑合,于是守护线程应运而生。

所谓的守护线程,指的是程序运行时在后台提供的一种通用服务的线程。比如垃圾回收线程就是一个很称职的守护者,并且这种线程并不属于程序中不可或缺的部分。因此,当所有的非守护线程结束时,程序也就终止了,同时会杀死进程中的所有守护线程。反过来说,只要任何非守护线程还在运行,程序就不会终止。

事实上,User Thread(用户线程)和Daemon Thread(守护线程)从本质上来说并没有什么区别,唯一的不同之处就在于虚拟机的离开:如果用户线程已经全部退出运行了,只剩下守护线程存在了,虚拟机也就退出了。 因为没有了被守护者,守护线程也就没有工作可做了,也就没有继续运行程序的必要了。

1.2 守护线程的使用与注意事项

守护线程并非只有虚拟机内部可以提供,用户也可以手动将一个用户线程设定/转换为守护线程。

在Thread类中提供了一个setDaemon(true)方法来将一个普通的线程(用户线程)设置为守护线程。

public final void setDaemon(boolean on);

在使用的过程中,有几点需要注意:
1.thread.setDaemon(true)必须在thread.start()之前设置,否则会抛出一个IllegalThreadStateException异常。这也就意味着不能把正在运行的常规线程设置为守护线程。 这点与操作系统中的守护进程有着明显的区别,守护进程是创建后,让进程摆脱原会话的控制+让进程摆脱原进程组的控制+让进程摆脱原控制终端的控制;所以说寄托于虚拟机的语言机制跟系统级语言有着本质上面的区别。

2.在Daemon线程中产生的新线程也是Daemon的。关于这一点又是与操作系统中的守护进程有着本质的区别:守护进程fork()出来的子进程不再是守护进程,尽管它把父进程的进程相关信息复制过去了,但是子进程的进程的父进程不是init进程,所谓的守护进程本质上说就是,当父进程挂掉,init就会收养该进程,然后文件0、1和2都是/dev/null,当前目录到/。

3.不是所有的应用都可以分配给Daemon线程来进行服务的,比如读写操作或者计算逻辑。因为这种应用可能在Daemon Thread还没来得及进行操作时,虚拟机已经退出了。这也就意味着,守护线程应该永远不去访问固有资源,如文件、数据库,因为它会在任何时候甚至在一个操作的中间发生中断。

下面以一个完成文件输出的守护线程任务作为例子:

import java.io.*;  

class TestRunnable implements Runnable {
    public void run(){
        try {
            Thread.sleep(1000); // 守护线程阻塞1秒后运行  
            File f = new File("daemon.txt");
            FileOutputStream os = new FileOutputStream(f,true);
            os.write("daemon".getBytes());
        } catch(IOException e1) {  
            e1.printStackTrace();  
        } catch(InterruptedException e2) {  
            e2.printStackTrace();  
        }  
    }  
}  

public class TestDemo2 {
    public static void main(String[] args) throws InterruptedException {
        Runnable tr = new TestRunnable();
        Thread thread = new Thread(tr);
        thread.setDaemon(true); // 设置守护线程(必须在thread.start()之前)
        thread.start(); // 开始执行分进程
    }
}

上面这段代码的运行结果是文件daemon.txt中没有daemon字符串。
但是如果把thread.setDaemon(true);这行代码注释掉,文件daemon.txt是可以被写入daemon字符串的,因为这个时候这个线程就是普通的用户线程了。
简单理解就是,JRE判断程序是否执行结束的标准是所有的前台线程(用户线程)执行完毕了,而不管后台线程(守护线程)的状态。

1.3 守护线程的应用场景

前面说了那么多,那么Daemon Thread的实际应用在那里呢?举个例子,Web服务器中的Servlet,在容器启动时,后台都会初始化一个服务线程,即调度线程,负责处理http请求,然后每个请求过来,调度线程就会从线程池中取出一个工作者线程来处理该请求,从而实现并发控制的目的。也就是说,一个实际应用在Java的线程池中的调度线程。

1.4 总结

从我的理解,守护线程就是用来告诉JVM,我的这个线程是一个低级别的线程,不需要等待它运行完才退出,让JVM喜欢什么时候退出就退出,不用管这个线程。
在日常的业务相关的CRUD开发中,其实并不会关注到守护线程这个概念,也几乎不会用上。
但是如果要往更高的地方走的话,这些深层次的概念还是要了解一下的,比如一些框架的底层实现。

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

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

相关文章

Java发送(QQ)邮箱、验证码发送

前言 使用Java应用程序发送 E-mail 十分简单,但是首先需要在项目中导入 JavaMail API 和Java Activation Framework (JAF) 的jar包。 菜鸟教程提供的下载链接: JavaMail mail.jar 1.4.5JAF(版本 1.1.1) activation.jar 1、准备…

C语言“牵手”拼多多商品详情数据方法,拼多多商品详情API接口,拼多多API申请指南

拼多多是中国最大的自营式电商企业,在线销售计算机、手机及其它数码产品、家电、汽车配件、服装与鞋类、奢侈品、家居与家庭用品、化妆品与其它个人护理用品、食品与营养品、书籍与其它媒体产品、母婴用品与玩具、体育与健身器材以及虚拟商品等。 拼多多平台的商品…

容器编排学习(十)控制器介绍与使用

一 控制器 控制器是 k8s内置的管理工具。可以帮助用户实现 Pod的自动部署、自维护、扩容、滚动更新等功能的自动化程序。 为什么要使用控制器? 有大量的 Pod需要维护管理需要维护 Pod的健康状态控制器可以像机器人一样可以替用户完成维护管理的工作 二 Deployment 1 概…

ROS学习笔记(四)---使用 VScode 启动launch文件运行多个节点

ROS学习笔记文章目录 01. ROS学习笔记(一)—Linux安装VScode 02. ROS学习笔记(二)—使用 VScode 开发 ROS 的Python程序(简例) 03. ROS学习笔记(三)—好用的终端Terminator 一、什么是launch文件 虽然说Terminator终端是能够比较方便直观的看运行的节点…

Spring-MVC的文件上传,下载的技术攻克

目录 一.前言 二.文件上传 文件上传的步骤: 三.文件下载 四.多文件上传 一.前言 SpringMVC的文件上传下载的主要作用是让用户能够将文件上传到服务器或从服…

消息队列基本原理和选型对比

消息队列使用场景 消息队列中间件是分布式系统中重要的组件,主要解决应用耦合,异步消息,削峰填谷等问题。实现高性能、高可用、可伸缩和最终一致性架构。 解耦:多个服务监听、处理同一条消息,避免多次 rpc 调用。 异步…

计算机网络基础知识(非常详细)

1. 网络模型 1.1 OSI 七层参考模型 七层模型,亦称 OSI(Open System Interconnection)参考模型,即开放式系统互联,是网络通信的标准模型。一般称为 OSI 参考模型或七层模型。 它是一个七层的、抽象的模型体&#xff…

Web学习笔记-React(组合Components)

笔记内容转载自 AcWing 的 Web 应用课讲义,课程链接:AcWing Web 应用课。 CONTENTS 1. 创建父组件2. 从上往下传递数据3. 传递子节点4. 从下往上调用函数 本节内容是组件与组件之间的组合,例如用不同组件构成 DOM 树,以及给不同的…

看完这篇 教你玩转渗透测试靶机Vulnhub——Momentum:2

Vulnhub靶机Momentum:2渗透测试详解 Vulnhub靶机介绍:Vulnhub靶机下载:Vulnhub靶机安装:Vulnhub靶机漏洞详解:①:信息收集:②:漏洞发现:③:文件上传漏洞利用:…

【C++基础】8. 函数

文章目录 【 1. 函数的定义 】【 2. 函数声明 】【 3. 调用函数 】【 4. 函数参数 】4.1 传值调用4.2 指针调用4.3 引用调用 【 5. 形参默认值 】【 6. lambda函数 】 函数是一组一起执行一个任务的语句。每个 C 程序都至少有一个函数,即主函数 main() 。可以把代码…

Fiddler工具使用汇总

Fiddler工作原理 fiddler作为一个代理服务器,跟浏览器建立连接之后,浏览器像目标服务器发送的请求都会经过fiddler代理,所以fiddler可以捕获到http(s)请求,从而可以解释、分析、甚至重写发出去的http&…

[De1CTF 2019]SSRF Me | BUUCTF

根据题目名我们知道这是一道SSRF的题目 它允许攻击者在受害服务器上发起未经授权的网络请求 分析 在buuctf上有一个提示 也就是说flag在 网站的flag.txt 访问主页 很明显是段flask代码 格式化后 from flask import Flask, request # 导入Flask和request模块 import sock…

设备管理系统的优势是什么?设备管理系统对企业运营管理有什么帮助?

传统的设备报修维护方式存在一些问题,例如指派传递速度慢和故障信息不准确等。然而,使用设备管理系统就可以轻松地解决这些问题,并且报修全流程只需短短的30秒。设备管理系统具有许多优势,首先它支持多种渠道的报修,包…

《TCP/IP网络编程》阅读笔记--进程间通信

目录 1--进程间通信 2--pipe()函数 3--代码实例 3-1--pipe1.c 3-2--pipe2.c 3-3--pipe3.c 3-4--保存信息的回声服务器端 1--进程间通信 为了实现进程间通信,使得两个不同的进程间可以交换数据,操作系统必须提供两个进程可以同时访问的内存空间&am…

初出茅庐的小李博客之数制与编码知识

模拟量与数字量: 数字量和模拟量是两种用于表示和处理不同类型数据的概念,常见于电子和计算机系统中。它们在信号处理、传感器技术、通信和控制系统中有不同的应用。 1. 数字量(Digital): 数字量是离散的&#xff0…

06文本搜索工具——grep以及正则表达式

一、grep工具的使用 可以通过返回状态码判断文件有没有这个数据,有状态码为0,没有为1。文件不存在状态码为2 -o: 二、正则表达式 1、基本正则表达式 .为匹配任意字符,..两个两个匹配任意字符,...三个三个匹配任意字符 …

群拼团接龙小程序源码功能和开发

针对微信群开发的拼团接龙小程序,有点快团团的味道。是做私域非常不错的一款小程序。 小程序基于Uniapp开发,目前适配了微信小程序。 接龙: 在小程序中可以创建自定义接龙,不需要复杂的申请流程。 商品发布: 接龙…

模板测试和深度测试在cocoscreator中的应用

模板测试(Stencil Test): 当片段着色器处理完一个片段之后,模板测试(Stencil Test)会开始执行,和深度测试一样,它也可能会丢弃片段。接下来,被保留的片段会进入深度测试,它可能会丢弃更多的片段。模板测试…

React 开发一个移动端项目(1)

技术栈: 项目搭建:React 官方脚手架 create-react-appreact hooks状态管理:redux 、 redux-thunkUI 组件库:antd-mobileajax请求库:axios路由:react-router-dom 以及 historyCSS 预编译器:sass…

Web开发后端总结

Web后端开发现在基本上都是基于标准的三层架构进行开发的,在三层架构当中,Controller控制器层 - 负责接收请求响应数据,Service - 业务层负责具体的业务逻辑处理,而Dao - 数据访问层也叫持久层,就是用来处理数据访问操…