網上對Java的Daemon線程的說法很多,看的人頭暈。
所以自己就來總結一下:
Java語言自己可以建立兩種進程“使用者線程”和“守護線程”
使用者線程:就是我們平時建立的普通線程.
守護線程:主要是用來服務使用者線程.
那麼如何來區分這兩種線程呢?
其實在JDK的文檔中已經說明的很清楚了:
* The Java Virtual Machine exits when the only threads running are all * daemon threads.
即:
當線程只剩下守護線程的時候,JVM就會退出.但是如果還有其他的任意一個使用者線程還在,JVM就不會退出.
下面我們用實驗來說明,當線程只剩下守護線程的時候,JVM就會退出.
代碼如下:
public class DaemonRunner implements Runnable { public void run() { while (true) { for (int i = 1; i <= 100; i++) { System.out.println(i); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } } public static void main(String[] args) { Thread daemonThread = new Thread(new DaemonRunner()); // 設定為守護進程 daemonThread.setDaemon(true); daemonThread.start(); System.out.println("isDaemon = " + daemonThread.isDaemon()); Scanner scanner = new Scanner(System.in); // 接受輸入,使程式在此停頓,一旦接受到使用者輸入,main線程結束,JVM退出! scanner.next();
//AddShutdownHook方法增加JVM停止時要做處理事件:
//當JVM退出時,列印JVM Exit語句. Runtime.getRuntime().addShutdownHook(new Thread(){ @Override public void run() { // TODO Auto-generated method stub System.out.println("JVM Exit!"); } }); }}
當程式啟動並執行時候,Daemon線程會不斷的在控制台列印數字,而main線程是一個使用者線程由於”scanner.next()”
等待使用者輸入,屬於阻塞了.此時JVM當然不會退出.
驗證步驟:
這個時候只要我們確定目前使用者線程只有一個,即只要main線程退出,然後檢查JVM是否真的退出了。
那麼我們如何確定當前的JVM虛擬機器中的,當前的使用者線程和daemon有多少呢?
我們可以用JDK中內建的查看堆棧工具jstack.
jstack 3308(即當前要探測的JVM進程的進程ID)
得到結果如下:
我們會看到當前JVM進程中跑著很多線程,但是只有main線程是使用者線程,其他線程要不是daemon線程(如Low Memory Detector或Thread-0),要不就是虛擬機器內部線程(如VM Thread 和VM Periodic Task Thread,這些線程我們不用考慮).
因此當使用者線程main線程退出時(在本程式中,在控制台輸入一個字元然後斷行符號),如果JVM確實退出了的話,會調用ShutDownHook在控制台上列印“JVM Exit!.”
如果沒有退出的話,當然就不會列印了.
驗證結果:
控制台成功列印“JVM Exit!”,JVM退出!