日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

JVM 中的守护线程

發布時間:2025/3/21 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 JVM 中的守护线程 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

在之前的《詳解JVM如何處理異常》提到了守護線程,當時沒有詳細解釋,所以打算放到今天來解釋說明一下JVM守護線程的內容。

特點

  • 通常由JVM啟動
  • 運行在后臺處理任務,比如垃圾回收等
  • 用戶啟動線程執行結束或者JVM結束時,會等待所有的非守護線程執行結束,但是不會因為守護線程的存在而影響關閉。

判斷線程是否為守護線程

判斷一個線程是否為守護線程,主要依據如下的內容

?

1 2 3 4 5 6 7 8 9 10 11 12 13 /* Whether or not the thread is a daemon thread. */ private boolean daemon = false;/** * Tests if this thread is a daemon thread. * * @return <code>true</code> if this thread is a daemon thread; * <code>false</code> otherwise. * @see #setDaemon(boolean) */ public final boolean isDaemon() {return daemon; }

下面我們進行一些簡單的代碼,驗證一些關于守護線程的特性和一些猜測。

輔助方法

打印線程信息的方法,輸出線程的組,是否為守護線程以及對應的優先級。

?

1 2 3 4 5 6 7 8 9 private static void dumpAllThreadsInfo() {Set<Thread> threadSet = Thread.getAllStackTraces().keySet();for(Thread thread: threadSet) {System.out.println("dumpAllThreadsInfo thread.name=" + thread.getName()+ ";group=" + thread.getThreadGroup()+ ";isDaemon=" + thread.isDaemon()+ ";priority=" + thread.getPriority());} }

線程睡眠的方法

?

1 2 3 4 5 6 7 8 private static void makeThreadSleep(long durationInMillSeconds) {try {Thread.sleep(durationInMillSeconds);} catch (InterruptedException e) {e.printStackTrace();}}

驗證普通的(非守護線程)線程會影響進程(JVM)退出

?

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 private static void testNormalThread() {long startTime = System.currentTimeMillis();new Thread("NormalThread") {@Overridepublic void run() {super.run();//保持睡眠,確保在執行dumpAllThreadsInfo時,該線程不會因為退出導致dumpAllThreadsInfo無法打印信息。makeThreadSleep(10 * 1000);System.out.println("startNormalThread normalThread.time cost=" + (System.currentTimeMillis() - startTime));}}.start();//主線程暫定3秒,確保子線程都啟動完成makeThreadSleep(3 * 1000);dumpAllThreadsInfo();System.out.println("MainThread.time cost = " + (System.currentTimeMillis() - startTime)); }

獲取輸出日志

?

1 2 3 4 5 6 7 8 9 10 dumpAllThreadsInfo thread.name=Signal Dispatcher;group=java.lang.ThreadGroup[name=system,maxpri=10];isDaemon=true;priority=9 dumpAllThreadsInfo thread.name=Attach Listener;group=java.lang.ThreadGroup[name=system,maxpri=10];isDaemon=true;priority=9 dumpAllThreadsInfo thread.name=Monitor Ctrl-Break;group=java.lang.ThreadGroup[name=main,maxpri=10];isDaemon=true;priority=5 dumpAllThreadsInfo thread.name=Reference Handler;group=java.lang.ThreadGroup[name=system,maxpri=10];isDaemon=true;priority=10 dumpAllThreadsInfo thread.name=main;group=java.lang.ThreadGroup[name=main,maxpri=10];isDaemon=false;priority=5 dumpAllThreadsInfo thread.name=NormalThread;group=java.lang.ThreadGroup[name=main,maxpri=10];isDaemon=false;priority=5 dumpAllThreadsInfo thread.name=Finalizer;group=java.lang.ThreadGroup[name=system,maxpri=10];isDaemon=true;priority=8 MainThread.time cost = 3009 startNormalThread normalThread.time cost=10003 Process finished with exit code 0 結束進程

我們根據上面的日志,我們可以發現

  • startNormalThread normalThread.time cost=10003代表著子線程執行結束,先于后面的進程結束執行。
  • Process finished with exit code 0?代表 結束進程

以上日志可以驗證進程是在我們啟動的子線程結束之后才退出的。

驗證JVM不等待守護線程就會結束

其實上面的例子也可以驗證JVM不等待JVM啟動的守護線程(Reference Handler,Signal Dispatcher等)執行結束就退出。

這里我們再次用一段代碼驗證一下JVM不等待用戶啟動的守護線程結束就退出的事實。

?

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 private static void testDaemonThread() {long startTime = System.currentTimeMillis();Thread daemonThreadSetByUser = new Thread("daemonThreadSetByUser") {@Overridepublic void run() {makeThreadSleep(10 * 1000);super.run();System.out.println("daemonThreadSetByUser.time cost=" + (System.currentTimeMillis() - startTime));}};daemonThreadSetByUser.setDaemon(true);daemonThreadSetByUser.start();//主線程暫定3秒,確保子線程都啟動完成makeThreadSleep(3 * 1000);dumpAllThreadsInfo();System.out.println("MainThread.time cost = " + (System.currentTimeMillis() - startTime)); }

上面的結果得到的輸出日志為

?

1 2 3 4 5 6 7 8 9 10 dumpAllThreadsInfo thread.name=Signal Dispatcher;group=java.lang.ThreadGroup[name=system,maxpri=10];isDaemon=true;priority=9 dumpAllThreadsInfo thread.name=Attach Listener;group=java.lang.ThreadGroup[name=system,maxpri=10];isDaemon=true;priority=9 dumpAllThreadsInfo thread.name=Monitor Ctrl-Break;group=java.lang.ThreadGroup[name=main,maxpri=10];isDaemon=true;priority=5 dumpAllThreadsInfo thread.name=Reference Handler;group=java.lang.ThreadGroup[name=system,maxpri=10];isDaemon=true;priority=10 dumpAllThreadsInfo thread.name=main;group=java.lang.ThreadGroup[name=main,maxpri=10];isDaemon=false;priority=5 dumpAllThreadsInfo thread.name=daemonThreadSetByUser;group=java.lang.ThreadGroup[name=main,maxpri=10];isDaemon=true;priority=5 dumpAllThreadsInfo thread.name=Finalizer;group=java.lang.ThreadGroup[name=system,maxpri=10];isDaemon=true;priority=8 MainThread.time cost = 3006Process finished with exit code 0

我們可以看到,上面的日志沒有類似daemonThreadSetByUser.time cost=的信息。可以確定JVM沒有等待守護線程結束就退出了。

注意:

  • 新的線程是否初始為守護線程,取決于啟動該線程的線程是否為守護線程。
  • 守護線程默認啟動的線程為守護線程,非守護線程啟動的線程默認為非守護線程。
  • 主線程(非守護線程)啟用一個守護線程,需要調用Thread.setDaemon來設置啟動線程為守護線程。

關于Priority與守護線程的關系

有一種傳言為守護線程的優先級要低,然而事實是

  • 優先級與是否為守護線程沒有必然的聯系
  • 新的線程的優先級與創建該線程的線程優先級一致。
  • 但是建議將守護線程的優先級降低一些。

感興趣的可以自己驗證一下(其實上面的代碼已經有驗證了)

from:?https://droidyue.com/blog/2018/12/16/daemon-thread-in-java/?

總結

以上是生活随笔為你收集整理的JVM 中的守护线程的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。