网易首页 > 网易号 > 正文 申请入驻

额!Java中用户线程和守护线程区别这么大?

0
分享至

  【CSDN 编者按】Java 语言中线程分为两类:用户线程和守护线程,而二者之间的区别却鲜有人知,本文带大家来看二者之间的区别,以及守护线程的一些事项和使用场景。文中通过示例代码介绍的非常详细,相信对大家的学习或者工作具有一定的参考学习价值。

  作者 | 王磊 责编 | 欧阳姝黎

  在 Java 语言中线程分为两类:用户线程和守护线程,而二者之间的区别却鲜有人知,所以本文磊哥带你来看二者之间的区别,以及守护线程需要注意的一些事项。

  
默认用户线程

  Java 语言中无论是线程还是线程池,默认都是用户线程,因此用户线程也被称为普通线程。

  以线程为例,想要查看线程是否为守护线程只需通过调用 isDaemon() 方法查询即可,如果查询的值为 false 则表示不为守护线程,自然也就属于用户线程了,如下代码所示:

  public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("我是子线程");

System.out.println("子线程==守护线程:" + thread.isDaemon());
System.out.println("主线程==守护线程:" + Thread.currentThread().isDaemon());

  以上程序的执行结果为:

  从上述结果可以看出,默认情况下主线程和创建的新线程都为用户线程

PS:Thread.currentThread() 的意思是获取执行当前代码的线程实例。

  
主动修改为守护线程

  守护线程(Daemon Thread)也被称之为后台线程或服务线程,守护线程是为用户线程服务的,当程序中的用户线程全部执行结束之后,守护线程也会跟随结束。

  守护线程的角色就像“服务员”,而用户线程的角色就像“顾客”,当“顾客”全部走了之后(全部执行结束),那“服务员”(守护线程)也就没有了存在的意义,所以当一个程序中的全部用户线程都结束执行之后,那么无论守护线程是否还在工作都会随着用户线程一块结束,整个程序也会随之结束运行。

  那如何将默认的用户线程修改为守护线程呢?

  这个问题要分为两种情况来回答,首先如果是线程,则可以通过设置 setDaemon(true) 方法将用户线程直接修改为守护线程,而如果是线程池则需要通过 ThreadFactory 将线程池中的每个线程都为守护线程才行,接下来我们分别来实现一下。

  2.1 设置线程为守护线程

  如果使用的是线程,可以通过 setDaemon(true) 方法将线程类型更改为守护线程,如下代码所示:

  public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("我是子线程");

// 设置子线程为守护线程
thread.setDaemon(true);
System.out.println("子线程==守护线程:" + thread.isDaemon());
System.out.println("主线程==守护线程:" + Thread.currentThread().isDaemon());

  以上程序的执行结果为:

  2.2 设置线程池为守护线程

  要把线程池设置为守护线程相对来说麻烦一些,需要将线程池中的所有线程都设置成守护线程,这个时候就需要使用 ThreadFactory 来定义线程池中每个线程的线程类型了,具体实现代码如下:

  // 创建固定个数的线程池
ExecutorService threadPool = Executors.newFixedThreadPool(10, new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r);
// 设置线程为守护线程
t.setDaemon(false);
return t;

  如下图所示:

  如上图所示,可以看出,整个程序中有 10 个守护线程都是我创建的。其他几种创建线程池的设置方式类似,都是通过 ThreadFactory 统一设置的,这里就不一一列举了。

  
守护线程 VS 用户线程

  通过前面的学习我们可以创建两种不同的线程类型了,那二者有什么差异呢?接下来我们使用一个小示例来看一下。

  下面我们创建一个线程,分别将这个线程设置为用户线程和守护线程,在每个线程中执行一个 for 循环,总共执行 10 次信息打印,每次打印之后休眠 100 毫秒,来观察程序的运行结果。

  3.1 用户线程

  新建的线程默认就是用户线程,因此我们无需对线程进行任何特殊的处理,执行 for 循环即可(总共执行 10 次信息打印,每次打印之后休眠 100 毫秒),实现代码如下:

  
* Author:Java中文社群
public class DaemonExample {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 1; i <= 10; i++) {
// 打印 i 信息
System.out.println("i:" + i);
try {
// 休眠 100 毫秒
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();


// 启动线程
thread.start();

  以上程序执行结果如下:

  从上述结果可以看出,当程序执行完 10 次打印之后才会正常结束进程。

  3.2 守护线程

  

* Author:Java中文社群
public class DaemonExample {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 1; i <= 10; i++) {
// 打印 i 信息
System.out.println("i:" + i);
try {
// 休眠 100 毫秒
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();


// 设置为守护线程
thread.setDaemon(true);
// 启动线程
thread.start();

  以上程序执行结果如下:

  从上述结果可以看出,当线程设置为守护线程之后,整个程序不会等守护线程 for 循环 10 次之后再进行关闭,而是当主线程结束之后,守护线程只执行了一次循环就结束运行了,由此可以看出守护线程和用户线程的不同。

  3.3 小结

  守护线程是为用户线程服务的,当一个程序中的所有用户线程都执行完成之后程序就会结束运行,程序结束运行时不会管守护线程是否正在运行,由此我们可以看出守护线程在 Java 体系中权重是比较低的。

  
守护线程注意事项

  守护线程的使用需要注意以下三个问题:

  守护线程的设置 setDaemon(true) 必须要放在线程的 start() 之前,否则程序会报错。

  在守护线程中创建的所有子线程都是守护线程。

  使用 jojn() 方法会等待一个线程执行完,无论此线程是用户线程还是守护线程。

  接下来我们分别演示一下,以上的注意事项。

  4.1 setDaemon 执行顺序

  当我们将 setDaemon(true) 设置在 start() 之后,如下代码所示:

  public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 1; i <= 10; i++) {
// 打印 i 信息
System.out.println("i:" + i + ",isDaemon:" +
Thread.currentThread().isDaemon());
try {
// 休眠 100 毫秒
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();


// 启动线程
thread.start();
// 设置为守护线程
thread.setDaemon(true);

  以上程序执行结果如下:

  从上述结果可以看出,当我们将 setDaemon(true) 设置在 start() 之后,不但程序的执行会报错,而且设置的守护线程也不会生效。

  4.2 守护线程的子线程public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {

  }
});
System.out.println("守护线程的子线程 thread2 isDaemon:" +
thread2.isDaemon());
}
});
// 设置为守护线程
thread.setDaemon(true);
// 启动线程
thread.start();

  Thread.sleep(1000);
}

  以上程序执行结果如下:

  从上述结果可以看出,守护线程中创建的子线程,默认情况下也属于守护线程。

  4.3 join 与守护线程

  通过 3.2 部分的内容我们可以看出,默认情况下程序结束并不会等待守护线程执行完,而当我们调用线程的等待方法 join() 时,执行的结果就会和 3.2 的结果有所不同,下面我们一起来看吧,示例代码如下:

  public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 1; i <= 10; i++) {
// 打印 i 信息
System.out.println("i:" + i);
try {
// 休眠 100 毫秒
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();


// 设置为守护线程
thread.setDaemon(true);
// 启动线程
thread.start();
// 等待线程执行完
thread.join();
System.out.println("子线程==守护线程:" + thread.isDaemon());
System.out.println("主线程==守护线程:" + Thread.currentThread().isDaemon());

  以上程序执行结果如下:

  通过上述结果我们可以看出,即使是守护线程,当程序中调用 join() 方法时,程序依然会等待守护线程执行完成之后再结束进程。

  
守护线程应用场景

  守护线程的典型应用场景就是垃圾回收线程,当然还有一些场景也非常适合使用守护线程,比如服务器端的健康检测功能,对于一个服务器来说健康检测功能属于非核心非主流的服务业务,像这种为了主要业务服务的业务功能就非常合适使用守护线程,当程序中的主要业务都执行完成之后,服务业务也会跟随者一起销毁。

  
守护线程的执行优先级

  首先来说,线程的类型(用户线程或守护线程)并不影响线程执行的优先级,如下代码所示,定义一个用户线程和守护线程,分别执行 10 万次循环,通过观察最后的打印结果来确认线程类型对程序执行优先级的影响。

  public class DaemonExample {
private static final int count = 100000;
public static void main(String[] args) throws InterruptedException {
// 定义任务
Runnable runnable = new Runnable() {
@Override
public void run() {
for (int i = 0; i < count; i++) {
System.out.println("执行线程:" + Thread.currentThread().getName());

// 创建守护线程 t1
Thread t1 = new Thread(runnable, "t1");
// 设置为守护线程
t1.setDaemon(true);
// 启动线程
t1.start();
// 创建用户线程 t2
Thread t2 = new Thread(runnable, "t2");
// 启动线程
t2.start();

  以上程序执行结果如下:

  通过上述结果可以看出,线程的类型不管是守护线程还是用户线程对程序执行的优先级是没有任何影响的,而当我们将 t2 的优先级调整为最大时,整个程序的运行结果就完全不同了,如下代码所示:

  public class DaemonExample {
private static final int count = 100000;
public static void main(String[] args) throws InterruptedException {
// 定义任务
Runnable runnable = new Runnable() {
@Override
public void run() {
for (int i = 0; i < count; i++) {
System.out.println("执行线程:" + Thread.currentThread().getName());

// 创建守护线程 t1
Thread t1 = new Thread(runnable, "t1");
// 设置为守护线程
t1.setDaemon(true);
// 启动线程
t1.start();
// 创建用户线程 t2
Thread t2 = new Thread(runnable, "t2");
// 设置 t2 的优先级为最高
t2.setPriority(Thread.MAX_PRIORITY);
// 启动线程
t2.start();

  以上程序执行结果如下:

  通过上述的结果可以看出,程序的类型和程序执行的优先级是没有任何关系,当新创建的线程默认的优先级都是 5 时,无论是守护线程还是用户线程,它们执行的优先级都是相同的,当将二者的优先级设置不同时,执行的结果也会随之改变(优先级设置的越高,最早被执行的概率也越大)。

  总结

  在 Java 语言中线程分为用户线程和守护线程,守护线程是用来为用户线程服务的,当一个程序中的所有用户线程都结束之后,无论守护线程是否在工作都会跟随用户线程一起结束。守护线程从业务逻辑层面来看权重比较低,但对于线程调度器来说无论是守护线程还是用户线程,在优先级相同的情况下被执行的概率都是相同的。守护线程的经典使用场景是垃圾回收线程,守护线程中创建的线程默认情况下也都是守护线程。

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
彻底炸锅!世界杯被要求禁止凯恩式点球,英格兰骗门将太耍赖

彻底炸锅!世界杯被要求禁止凯恩式点球,英格兰骗门将太耍赖

一隅非生
2026-06-19 08:05:13
华为注册“世界”商标通过初审!

华为注册“世界”商标通过初审!

芯智讯
2026-06-19 13:34:35
甘肃通渭李女士事件大反转!聊天记录曝光:从被动接受到主动迎合

甘肃通渭李女士事件大反转!聊天记录曝光:从被动接受到主动迎合

火山詩话
2026-06-19 08:19:30
争议!央视社媒删梅西内容 网友爆料:23点紧急通知 直播别给特写

争议!央视社媒删梅西内容 网友爆料:23点紧急通知 直播别给特写

念洲
2026-06-19 09:28:22
墨西哥主帅:与韩国的比赛很艰苦;我不喜欢李刚仁的发色

墨西哥主帅:与韩国的比赛很艰苦;我不喜欢李刚仁的发色

懂球帝
2026-06-19 15:53:25
暴雨驱避雨母子后续!涉事宝妈颜值很高,老字号餐饮口碑彻底崩塌

暴雨驱避雨母子后续!涉事宝妈颜值很高,老字号餐饮口碑彻底崩塌

火山詩话
2026-06-19 06:11:26
乱了!世界杯赛后爆发大规模冲突,比起6比0,更惨的是断腿重伤

乱了!世界杯赛后爆发大规模冲突,比起6比0,更惨的是断腿重伤

观察鉴娱
2026-06-19 14:51:34
宝妈避雨被赶后续:大批顾客退单,商家道歉也无果,门店口碑崩了

宝妈避雨被赶后续:大批顾客退单,商家道歉也无果,门店口碑崩了

千言娱乐记
2026-06-18 18:59:27
匪夷所思!“濮阳护士长”悄悄上热搜,“19分28秒”等标签满天飞

匪夷所思!“濮阳护士长”悄悄上热搜,“19分28秒”等标签满天飞

火山詩话
2026-06-18 17:00:53
《抓特务》为何票房扑街?太陈旧,是次因,“瘸驴叙事”,是主因

《抓特务》为何票房扑街?太陈旧,是次因,“瘸驴叙事”,是主因

马庆云的影音娱
2026-06-19 14:39:29
一场迟到的“断舍离”,山水酒店连亏6年负债5.25亿元,中青旅忍痛切割

一场迟到的“断舍离”,山水酒店连亏6年负债5.25亿元,中青旅忍痛切割

华夏时报
2026-06-19 10:10:05
私生活混乱、被央视“开除”、陪睡上位,她身上哪个标签是真的?

私生活混乱、被央视“开除”、陪睡上位,她身上哪个标签是真的?

素衣读史
2026-06-18 21:37:31
山姆高层大逃亡,真相触目惊心

山姆高层大逃亡,真相触目惊心

新浪财经
2026-06-18 19:02:44
川大和港理工研究发现:一个地方经济越落后,女生自拍P图越厉害

川大和港理工研究发现:一个地方经济越落后,女生自拍P图越厉害

必记本
2026-06-12 14:03:52
泽连斯基的眼泪

泽连斯基的眼泪

近距离
2026-06-18 17:12:18
小国佛得角火了!逼平西班牙的背后还藏着中国的托举……这届世界杯四支新军都没白来

小国佛得角火了!逼平西班牙的背后还藏着中国的托举……这届世界杯四支新军都没白来

新民周刊
2026-06-19 16:07:33
孙兴慜57分钟0射门引热议:被嘲像女星 在儿童区冲刺 亚洲一哥们

孙兴慜57分钟0射门引热议:被嘲像女星 在儿童区冲刺 亚洲一哥们

颜小白的篮球梦
2026-06-19 14:04:45
整治冒充、伪装、夹带、黑灰产!中央网信办专项治理账号乱象

整治冒充、伪装、夹带、黑灰产!中央网信办专项治理账号乱象

南方都市报
2026-06-19 10:41:10
多给一天时间?伊朗队请求再次被拒,美国:比赛当天必须离开

多给一天时间?伊朗队请求再次被拒,美国:比赛当天必须离开

全景体育V
2026-06-19 18:10:55
腿被踢断,告别世界杯!24岁新星最新伤情,主帅表态,肇事者发声

腿被踢断,告别世界杯!24岁新星最新伤情,主帅表态,肇事者发声

萌兰聊个球
2026-06-19 10:56:25
2026-06-19 20:07:00
CSDN incentive-icons
CSDN
成就一亿技术人
26666文章数 242291关注度
往期回顾 全部

科技要闻

Anthropic被禁,智谱却涨疯了

头条要闻

婚礼短片现"别人老公老婆"新娘忍整场 不料有更离谱的

头条要闻

婚礼短片现"别人老公老婆"新娘忍整场 不料有更离谱的

体育要闻

世界杯最不知名球员,没上场先涨粉600万

娱乐要闻

吴倩自曝小时被爸爸打掉牙齿硬吞进肚

财经要闻

Token低价陷阱

汽车要闻

惊出冷汗!重庆实测奥迪A5L,华为智驾这波操作绝了…

态度原创

本地
时尚
健康
公开课
军事航空

本地新闻

世界杯黑马佛得角:河北人开超市,温州人当老板

夏天上衣穿短不穿长,看看下面这几款短上衣,显高舒适显比例

吃粽子的3条保胃法则,消化科医生推荐

公开课

李玫瑾:为什么性格比能力更重要?

军事要闻

霸气!端午节最硬核的“龙舟”竞渡来了

无障碍浏览 进入关怀版