java高并發(fā)的用戶線程和守護線程詳解
守護線程是一種特殊的線程,在后臺默默地完成一些系統(tǒng)性的服務(wù),比如垃圾回收線程、JIT線程都是守護線程。與之對應(yīng)的是用戶線程,用戶線程可以理解為是系統(tǒng)的工作線程,它會完成這個程序需要完成的業(yè)務(wù)操作。如果用戶線程全部結(jié)束了,意味著程序需要完成的業(yè)務(wù)操作已經(jīng)結(jié)束了,系統(tǒng)可以退出了。所以當系統(tǒng)只剩下守護進程的時候,java虛擬機會自動退出。
java線程分為用戶線程和守護線程,線程的daemon屬性為true表示是守護線程,false表示是用戶線程。
下面我們來看一下守護線程的一些特性。
程序只有守護線程時,系統(tǒng)會自動退出
package com.itsoku.chat03;
/**
* 微信公眾號:路人甲Java,專注于java技術(shù)分享(帶你玩轉(zhuǎn) 爬蟲、分布式事務(wù)、異步消息服務(wù)、任務(wù)調(diào)度、分庫分表、大數(shù)據(jù)等),喜歡請關(guān)注!
*/
public class Demo1 {
public static class T1 extends Thread {
public T1(String name) {
super(name);
}
@Override
public void run() {
System.out.println(this.getName() + "開始執(zhí)行," + (this.isDaemon() ? "我是守護線程" : "我是用戶線程"));
while (true) ;
}
}
public static void main(String[] args) {
T1 t1 = new T1("子線程1");
t1.start();
System.out.println("主線程結(jié)束");
}
}
運行上面代碼,結(jié)果如下:

可以看到主線程已經(jīng)結(jié)束了,但是程序無法退出,原因:子線程1是用戶線程,內(nèi)部有個死循環(huán),一直處于運行狀態(tài),無法結(jié)束。
再看下面的代碼:
package com.itsoku.chat03;
/**
* 微信公眾號:路人甲Java,專注于java技術(shù)分享(帶你玩轉(zhuǎn) 爬蟲、分布式事務(wù)、異步消息服務(wù)、任務(wù)調(diào)度、分庫分表、大數(shù)據(jù)等),喜歡請關(guān)注!
*/
public class Demo2 {
public static class T1 extends Thread {
public T1(String name) {
super(name);
}
@Override
public void run() {
System.out.println(this.getName() + "開始執(zhí)行," + (this.isDaemon() ? "我是守護線程" : "我是用戶線程"));
while (true) ;
}
}
public static void main(String[] args) {
T1 t1 = new T1("子線程1");
t1.setDaemon(true);
t1.start();
System.out.println("主線程結(jié)束");
}
}
運行結(jié)果:

程序可以正常結(jié)束了,代碼中通過 t1.setDaemon(true); 將t1線程設(shè)置為守護線程,main方法所在的主線程執(zhí)行完畢之后,程序就退出了。
結(jié)論:當程序中所有的用戶線程執(zhí)行完畢之后,不管守護線程是否結(jié)束,系統(tǒng)都會自動退出。
設(shè)置守護線程,需要在start()方法之前進行
package com.itsoku.chat03;
import java.util.concurrent.TimeUnit;
/**
* 微信公眾號:路人甲Java,專注于java技術(shù)分享(帶你玩轉(zhuǎn) 爬蟲、分布式事務(wù)、異步消息服務(wù)、任務(wù)調(diào)度、分庫分表、大數(shù)據(jù)等),喜歡請關(guān)注!
*/
public class Demo3 {
public static void main(String[] args) {
Thread t1 = new Thread() {
@Override
public void run() {
try {
TimeUnit.SECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
t1.start();
t1.setDaemon(true);
}
}
t1.setDaemon(true);是在t1的start()方法之后執(zhí)行的,執(zhí)行會報異常,運行結(jié)果如下:

線程daemon的默認值
我們看一下創(chuàng)建線程源碼,位于Thread類的init()方法中:
Thread parent = currentThread(); this.daemon = parent.isDaemon();
dameon的默認值為為父線程的daemon,也就是說,父線程如果為用戶線程,子線程默認也是用戶現(xiàn)場,父線程如果是守護線程,子線程默認也是守護線程。
示例代碼:
package com.itsoku.chat03;
import java.util.concurrent.TimeUnit;
/**
* 微信公眾號:路人甲Java,專注于java技術(shù)分享(帶你玩轉(zhuǎn) 爬蟲、分布式事務(wù)、異步消息服務(wù)、任務(wù)調(diào)度、分庫分表、大數(shù)據(jù)等),喜歡請關(guān)注!
*/
public class Demo4 {
public static class T1 extends Thread {
public T1(String name) {
super(name);
}
@Override
public void run() {
System.out.println(this.getName() + ".daemon:" + this.isDaemon());
}
}
public static void main(String[] args) throws InterruptedException {
System.out.println(Thread.currentThread().getName() + ".daemon:" + Thread.currentThread().isDaemon());
T1 t1 = new T1("t1");
t1.start();
Thread t2 = new Thread() {
@Override
public void run() {
System.out.println(this.getName() + ".daemon:" + this.isDaemon());
T1 t3 = new T1("t3");
t3.start();
}
};
t2.setName("t2");
t2.setDaemon(true);
t2.start();
TimeUnit.SECONDS.sleep(2);
}
}
運行代碼,輸出:
main.daemon:false
t1.daemon:false
t2.daemon:true
t3.daemon:true
t1是由主線程(main方法所在的線程)創(chuàng)建的,main線程是t1的父線程,所以t1.daemon為false,說明t1是用戶線程。
t2線程調(diào)用了 setDaemon(true);將其設(shè)為守護線程,t3是由t2創(chuàng)建的,所以t3默認線程類型和t2一樣,t2.daemon為true。
總結(jié)
1.java中的線程分為用戶線程和守護線程
2.程序中的所有的用戶線程結(jié)束之后,不管守護線程處于什么狀態(tài),java虛擬機都會自動退出
3.調(diào)用線程的實例方法setDaemon()來設(shè)置線程是否是守護線程
4.setDaemon()方法必須在線程的start()方法之前調(diào)用,在后面調(diào)用會報異常,并且不起效
5.線程的daemon默認值和其父線程一樣
本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
SpringBoot+Thymeleaf+ECharts實現(xiàn)大數(shù)據(jù)可視化(基礎(chǔ)篇)
本文主要介紹了SpringBoot+Thymeleaf+ECharts實現(xiàn)大數(shù)據(jù)可視化,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧<BR>2022-06-06
Windows下將JAVA?jar注冊成windows服務(wù)的方法
這篇文章主要介紹了Windows下將JAVA?jar注冊成windows服務(wù)的方法,本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-07-07
SpringBoot整合MyBatis四種常用的分頁方式(詳細總結(jié))
這篇文章詳細給大家總結(jié)了SpringBoot整合MyBatis四種常用的分頁方式,文中通過代碼示例為大家介紹的非常詳細,需要的朋友可以參考下2023-07-07
SpringBoot中使用AOP實現(xiàn)日志記錄功能
AOP的全稱是Aspect-Oriented Programming,即面向切面編程(也稱面向方面編程),它是面向?qū)ο缶幊蹋∣OP)的一種補充,目前已成為一種比較成熟的編程方式,本文給大家介紹了SpringBoot中使用AOP實現(xiàn)日志記錄功能,需要的朋友可以參考下2024-05-05
Java實現(xiàn)ATM系統(tǒng)超全面步驟解讀建議收藏
這篇文章主要為大家詳細介紹了用Java實現(xiàn)簡單ATM機功能,文中實現(xiàn)流程寫的非常清晰全面,具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-03-03

