java线程基础知识----java daemon线程
java线程是一个运用很广泛的重点知识,我们很有必要了解java的daemon线程.
1.首先我们必须清楚的认识到java的线程分为两类: 用户线程和daemon线程
A. 用户线程: 用户线程可以简单的理解为用户定义的线程,当然包括main线程(以前我错误的认为main线程也是一个daemon线程,但是慢慢的发现原来main线程不是,因为如果我再main线程中创建一个用户线程,并且打出日志,我们会发现这样一个问题,main线程运行结束了,但是我们的线程任然在运行).
B. daemon线程: daemon线程是为我们创建的用户线程提供服务的线程,比如说jvm的GC等等,这样的线程有一个非常明显的特征: 当用户线程运行结束的时候,daemon线程将会自动退出.(由此我们可以推出下面关于daemon线程的几条基本特点)
2. daemon 线程的特点:
A. 守护线程创建的过程中需要先调用setDaemon方法进行设置,然后再启动线程.否则会报出IllegalThreadStateException异常.(个人在想一个问题,为什么不能动态更改线程为daemon线程?有时间一个补上这个内容,现在给出一个猜测: 是因为jvm判断线程状态的时候,如果当前只存在一个线程Thread1,如果我们把这个线程动态更改为daemon线程,jvm会认为当前已经不存在用户线程而退出,稍后将会给出正确结论,抱歉!如果有哪位大牛看到,希望给出指点,谢谢!)
B. 由于daemon线程的终止条件是当前是否存在用户线程,所以我们不能指派daemon线程来进行一些业务操作,而只能服务用户线程.
C. daemon线程创建的子线程任然是daemon线程.
3. 针对上面给出的daemon线程的特点,我们进行如下验证:
A. 对应上面的A特点:
public class ThreadTest { public static void main(String[] args) throws InterruptedException { Thread thread1 = new Thread(new Thread2()); thread1.start(); thread1.setDaemon(true); Thread.sleep(10); System.out.println("用户线程退出"); } } class Thread2 implements Runnable{ @Override public void run() { try { Thread.sleep(1000); System.out.println("1+1="+(1+1)); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } 运行结果: Exception in thread "main" java.lang.IllegalThreadStateException at java.lang.Thread.setDaemon(Thread.java:1352) at ThreadTest.main(ThreadTest.java:5) 1+1=2
通过上面的例子我们可以发现,我们并不能动态的更改线程为daemon线程,源码解释如下:
java源码: public final void setDaemon(boolean on) { checkAccess(); if (isAlive()) { throw new IllegalThreadStateException(); } daemon = on; }
我们可以发现,在源码中如果我们的线程状态是alive的,我们的程序就会抛出异常.
B.对应上面的B特点:
public class ThreadTest { public static void main(String[] args) throws InterruptedException { Thread thread1 = new Thread(new Thread2()); thread1.setDaemon(true); thread1.start(); Thread.sleep(10); System.out.println("用户线程退出"); } } class Thread2 implements Runnable{ @Override public void run() { try { Thread.sleep(1000); System.out.println("1+1="+(1+1)); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } 运行结果: 用户线程退出
通过上面的例子我们可以看到,我们在daemon线程中进行相关的计算工作,但是我们并没有获取计算结果,因为用户线程main已经运行结束.
C.对应上面的C特点:
public class ThreadTest { public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(new Thread2()); thread.setDaemon(true); thread.start(); System.out.println("Thread是否时daemon线程"+thread.isDaemon()); Thread.sleep(100); System.out.println("用户线程退出"); } } class Thread2 implements Runnable{ @Override public void run() { Thread1 thread1 = new Thread1(); thread1.start(); System.out.println("Thread1是否是daemon线程"+thread1.isDaemon()); } } class Thread1 extends Thread{ public void run () { System.out.println("dosomething"); } } 运行结果: Thread是否时daemon线程true Thread1是否是daemon线程true dosomething 用户线程退出
源码解析:
private void init(ThreadGroup g, Runnable target, String name, long stackSize, AccessControlContext acc) { ...... this.daemon = parent.isDaemon(); this.priority = parent.getPriority(); ...... }
在进行Thread初始化的时候,会获取父进程的isDaemon来复制子进程的daemon.
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET制作智能桌面机器人:结合BotSharp智能体框架开发语音交互
· 软件产品开发中常见的10个问题及处理方法
· .NET 原生驾驭 AI 新基建实战系列:向量数据库的应用与畅想
· 从问题排查到源码分析:ActiveMQ消费端频繁日志刷屏的秘密
· 一次Java后端服务间歇性响应慢的问题排查记录
· 互联网不景气了那就玩玩嵌入式吧,用纯.NET开发并制作一个智能桌面机器人(四):结合BotSharp
· Vite CVE-2025-30208 安全漏洞
· 《HelloGitHub》第 108 期
· MQ 如何保证数据一致性?
· 一个基于 .NET 开源免费的异地组网和内网穿透工具