java 中有兩類線程:用戶線程和守護線程。
守護線程的作用是為用戶線程的運行提供服務,比如說 GC 線程。
輸出:
守護線程啟動 這個線程是守護線程嗎?Yes
關鍵在于 thread.setDaemon(true) 這段代碼。
特點一: setDaemon(true) 必須在 start() 之前,否則會有異常。你不能把正在運行的常規線程設置為守護線程。
特點二: 守護線程存在的目的是為用戶線程提供服務,因此如果用戶線程全部撤離,那么守護線程也就沒什么存在的必要了,所以虛擬機也就退出了。所以守護線程中的 finally 塊不一定會執行。
下面舉例驗證:
public class DaemonTest_02 { public static void main(String[] args) { Thread thread = new Thread(new DaemonRunner(), "DeamonRunner"); thread.setDaemon(true); thread.start(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } static class DaemonRunner implements Runnable { @Override public void run() { try { System.out.println("守護線程啟動"); System.out.println("這個線程是守護線程嗎?" + (Thread.currentThread().isDaemon() ? "Yes" : "No")); Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } finally { System.out.println("進入 finally 方法"); } } }}可能的一種輸出:
守護線程啟動 這個線程是守護線程嗎?Yes
main 方法執行完畢后虛擬機中已經沒有用戶線程了,虛擬機需要退出,所有守護線程立即終止,但是 finally 塊并沒有執行。因此在構建守護線程時,不能依靠 finally 塊中的內容來確保執行關閉或清理資源的邏輯。
特點三: 守護線程創建的新線程也是守護線程。
舉例說明:
public class DaemonTest_03 { public static void main(String[] args) { Thread thread = new Thread(new DaemonRunner(), "DeamonRunner"); thread.setDaemon(true); thread.start(); try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } } static class DaemonRunner implements Runnable { @Override public void run() { System.out.println("守護線程啟動"); System.out.println("這個線程是守護線程嗎:" + (Thread.currentThread().isDaemon()?"Yes":"No")); try { Thread thread = new Thread(new Runner(), "Runner"); // thread.setDaemon(true); 注意這里并沒有明確設置新線程為守護線程 thread.start(); Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } } } static class Runner implements Runnable { @Override public void run() { System.out.println("新線程啟動"); System.out.println("這個新線程是守護線程嗎:" + (Thread.currentThread().isDaemon()?"Yes":"No")); } }}輸出:
守護線程啟動 這個線程是守護線程嗎:Yes 新線程啟動 這個新線程是守護線程嗎:Yes
新聞熱點
疑難解答