Java守護(hù)線程和用戶線程的區(qū)別
前言:
在 Java 語言中,線程分為兩類:用戶線程和守護(hù)線程,默認(rèn)情況下我們創(chuàng)建的線程或線程池都是用戶線程,所以用戶線程也被稱之為普通線程。
想要查看線程到底是用戶線程還是守護(hù)線程,可以通過 Thread.isDaemon()
方法來判斷,如果返回的結(jié)果是 true 則為守護(hù)線程,反之則為用戶線程。
我們來測試一下默認(rèn)情況下線程和線程池屬于哪種線程類型?測試代碼如下:
import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; /** * 線程類型:守護(hù)線程 OR 用戶線程 */ public class ThreadType { public static void main(String[] args) { // 創(chuàng)建線程 Thread thread = new Thread(new Runnable() { @Override public void run() { //... } }); // 創(chuàng)建線程池 ThreadPoolExecutor threadPool = new ThreadPoolExecutor(10, 10, 0, TimeUnit.SECONDS, new LinkedBlockingQueue<>(100)); threadPool.submit(new Runnable() { @Override public void run() { System.out.println("ThreadPool 線程類型:" + (Thread.currentThread().isDaemon() == true ? "守護(hù)線程" : "用戶線程")); } }); System.out.println("Thread 線程類型:" + (thread.isDaemon() == true ? "守護(hù)線程" : "用戶線程")); System.out.println("main 線程類型:" + (Thread.currentThread().isDaemon() == true ? "守護(hù)線程" : "用戶線程")); } }
以上程序的執(zhí)行結(jié)果如下圖所示:
從上述結(jié)果可以看出,默認(rèn)情況下創(chuàng)建的線程和線程池都是用戶線程。
守護(hù)線程定義
守護(hù)線程(Daemon Thread)也被稱之為后臺線程或服務(wù)線程,守護(hù)線程是為用戶線程服務(wù)的,當(dāng)程序中的用戶線程全部執(zhí)行結(jié)束之后,守護(hù)線程也會(huì)跟隨結(jié)束。 守護(hù)線程的角色就像“服務(wù)員”,而用戶線程的角色就像“顧客”,當(dāng)“顧客”全部走了之后(全部執(zhí)行結(jié)束),那“服務(wù)員”(守護(hù)線程)也就沒有了存在的意義,所以當(dāng)一個(gè)程序中的全部用戶線程都結(jié)束執(zhí)行之后,那么無論守護(hù)線程是否還在工作都會(huì)隨著用戶線程一塊結(jié)束,整個(gè)程序也會(huì)隨之結(jié)束運(yùn)行。
創(chuàng)建守護(hù)線程
我們可以通過 Thread.setDaemon(true) 方法將線程設(shè)置為守護(hù)線程,比如以下代碼的實(shí)現(xiàn):
public static void main(String[] args) { Thread thread = new Thread(new Runnable() { @Override public void run() { //... } }); // 設(shè)置線程為守護(hù)線程 thread.setDaemon(true); System.out.println("Thread 線程類型:" + (thread.isDaemon() == true ? "守護(hù)線程" : "用戶線程")); System.out.println("main 線程類型:" + (Thread.currentThread().isDaemon() == true ? "守護(hù)線程" : "用戶線程")); }
以上程序的執(zhí)行結(jié)果如下圖所示:
將線程池設(shè)置為守護(hù)線程
要把線程池設(shè)置為守護(hù)線程相對來說麻煩一些,需要將線程池中的所有線程都設(shè)置成守護(hù)線程,這個(gè)時(shí)候就需要使用線程工廠 ThreadFactory 來設(shè)置了(線程池中的所有線程都是通過線程工廠創(chuàng)建的),
它的具體實(shí)現(xiàn)代碼如下:
public static void main(String[] args) throws InterruptedException { // 線程工廠(設(shè)置守護(hù)線程) ThreadFactory threadFactory = new ThreadFactory() { @Override public Thread newThread(Runnable r) { Thread thread = new Thread(r); // 設(shè)置為守護(hù)線程 thread.setDaemon(true); return thread; } }; // 創(chuàng)建線程池 ThreadPoolExecutor threadPool = new ThreadPoolExecutor(10, 10, 0, TimeUnit.SECONDS, new LinkedBlockingQueue<>(100), threadFactory); threadPool.submit(new Runnable() { @Override public void run() { System.out.println("ThreadPool 線程類型:" + (Thread.currentThread().isDaemon() == true ? "守護(hù)線程" : "用戶線程")); } }); Thread.sleep(2000); }
以上程序的執(zhí)行結(jié)果如下圖所示:
守護(hù)線程 VS 用戶線程
通過前面的內(nèi)容我們了解了什么是用戶線程和守護(hù)線程了,那二者有什么區(qū)別呢?接下來我們用一個(gè)小示例來觀察一下。 接下來我們將創(chuàng)建一個(gè)線程,分別將這個(gè)線程設(shè)置為用戶線程和守護(hù)線程,在每個(gè)線程中執(zhí)行一個(gè) for 循環(huán),總共執(zhí)行 10 次信息打印,每次打印之后休眠 100 毫秒,來觀察程序的運(yùn)行結(jié)果。
用戶線程
新建的線程默認(rèn)就是用戶線程,因此我們無需對線程進(jìn)行任何特殊的處理,執(zhí)行 for 循環(huán)即可(總共執(zhí)行 10 次信息打印,每次打印之后休眠 100 毫秒),
實(shí)現(xiàn)代碼如下:
public static void main(String[] args) throws InterruptedException { // 創(chuàng)建用戶線程 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(); } } } }); // 啟動(dòng)線程 thread.start(); }
以上程序的執(zhí)行結(jié)果如下圖所示:
從上述結(jié)果可以看出,當(dāng)程序執(zhí)行完 10 次打印之后才會(huì)正常結(jié)束進(jìn)程。
守護(hù)線程
public static void main(String[] args) throws InterruptedException { // 創(chuàng)建守護(hù)線程 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(); } } } }); // 設(shè)置為守護(hù)線程 thread.setDaemon(true); // 啟動(dòng)線程 thread.start(); }
以上程序執(zhí)行結(jié)果如下圖所示:
從上述結(jié)果可以看出,當(dāng)線程設(shè)置為守護(hù)線程之后,整個(gè)程序不會(huì)等守護(hù)線程 for 循環(huán) 10 次之后再進(jìn)行關(guān)閉,而是當(dāng)主線程結(jié)束之后,守護(hù)線程一次循環(huán)都沒執(zhí)行就結(jié)束了,由此可以看出守護(hù)線程和用戶線程的不同。
守護(hù)線程注意事項(xiàng)
守護(hù)線程的設(shè)置 setDaemon(true) 必須要放在線程的 start() 之前,否則程序會(huì)報(bào)錯(cuò)。也就是說在運(yùn)行線程之前,一定要先確定線程的類型,并且線程運(yùn)行之后是不允許修改線程的類型的。 接下來我們來演示一下,如果在程序運(yùn)行執(zhí)行再設(shè)置線程的類型會(huì)出現(xiàn)什么問題?
演示代碼如下:
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(); } } } }); // 啟動(dòng)線程 thread.start(); // 設(shè)置為守護(hù)線程 thread.setDaemon(true); }
以上程序執(zhí)行結(jié)果如下圖所示:
從上述結(jié)果可以看出,當(dāng)我們將 setDaemon(true) 設(shè)置在 start() 之后,不但程序的執(zhí)行會(huì)報(bào)錯(cuò),而且設(shè)置的守護(hù)線程也不會(huì)生效。
總結(jié)
在 Java 語言中線程分為兩類:用戶線程和守護(hù)線程,默認(rèn)情況下我們創(chuàng)建的線程或線程池都是用戶線程,守護(hù)線程是為用戶線程服務(wù)的,當(dāng)一個(gè)程序中的所有用戶線程都執(zhí)行完成之后程序就會(huì)結(jié)束運(yùn)行,程序結(jié)束運(yùn)行時(shí)不會(huì)管守護(hù)線程是否正在運(yùn)行,由此我們可以看出守護(hù)線程在 Java 體系中權(quán)重是比較低的,這就是守護(hù)線程和用戶線程的區(qū)別。
到此這篇關(guān)于Java守護(hù)線程和用戶線程的區(qū)別的文章就介紹到這了,更多相關(guān)Java 守護(hù)線程內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java反射中java.beans包學(xué)習(xí)總結(jié)
本篇文章通過學(xué)習(xí)Java反射中java.beans包,吧知識點(diǎn)做了總結(jié),并把相關(guān)內(nèi)容做了關(guān)聯(lián),對此有需要的朋友可以學(xué)習(xí)參考下。2018-02-02帶你了解Java數(shù)據(jù)結(jié)構(gòu)和算法之鏈表
這篇文章主要為大家介紹了Java數(shù)據(jù)結(jié)構(gòu)和算法之鏈表 ,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助2022-01-01使用FeignClient調(diào)用遠(yuǎn)程服務(wù)時(shí)整合本地的實(shí)現(xiàn)方法
這篇文章主要介紹了使用FeignClient調(diào)用遠(yuǎn)程服務(wù)時(shí)整合本地的實(shí)現(xiàn)方法,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03聊聊ResourceBundle和properties讀取配置文件的區(qū)別
這篇文章主要介紹了ResourceBundle和properties讀取配置文件的區(qū)別,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07