日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

【java读书笔记】ThreadGroup和钩子线程的使用

發布時間:2024/9/30 47 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【java读书笔记】ThreadGroup和钩子线程的使用 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

  • ThreadGroup介紹
    • ThreadGroup的基本操作
    • ThreadGroup的其他方法
  • 鉤子線程
    • 用hook線程模擬防重復啟動程序

ThreadGroup介紹

ThreadGroup并不能提供對線程的管理,ThreadGroup的主要功能是對線程進行組織,下面將詳細介紹ThreadGroup的主要方法。

ThreadGroup的基本操作

activeCount()用于獲取group中活躍的線程,這只是個估計值,并不能百分之百地保證數字一定正確,原因前面已經分析過,該方法會遞歸獲取其他子group中的活躍線程。

activeGroupCount()用于獲取group中活躍的子group,這也是一個近似估值,該方法也會遞歸獲取所有的子group。

getMaxPriority()用于獲取group的優先級,默認情況下,Group的優先級為10,在該group中,所有線程的優先級都不能大于group的優先級

getName()用于獲取group的名字。

getParent()用于獲取group的父group,如果父group不存在,則會返回null,比如system group的父group就為null。 list()該方法沒有返回值,執行該方法會將group中所有的活躍線程信息全部輸出到控制臺,也就是System.out。

parentOf(ThreadGroup g)會判斷當前group是不是給定group的父group,另外如果給定的group就是自己本身,那么該方法也會返回true。

setMaxPriority(int pri)會指定group的最大優先級,最大優先級不能超過父group的最大優先級,執行該方法不僅會改變當前group的最大優先級,還會改變所有子group的最大優先級。 下面我們給出一個簡單的例子來測試一下上面的幾個方法。

package com.wangwenjun.concurrent.chapter06;import java.util.concurrent.TimeUnit;public class ThreadGroupBasic {public static void main(String[] args) throws InterruptedException{/** Create a thread group and thread.*/ThreadGroup group = new ThreadGroup("group1");Thread thread = new Thread(group, () ->{while (true){try{TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e){e.printStackTrace();}}}, "thread");thread.setDaemon(true);thread.start();//make sure the thread is startedTimeUnit.MILLISECONDS.sleep(1);ThreadGroup mainGroup = Thread.currentThread().getThreadGroup();System.out.println("activeCount=" + mainGroup.activeCount());System.out.println("activeGroupCount=" + mainGroup.activeGroupCount());System.out.println("getMaxPriority=" + mainGroup.getMaxPriority());System.out.println("getName=" + mainGroup.getName());System.out.println("getParent=" + mainGroup.getParent());mainGroup.list();System.out.println("--------------------------");System.out.println("parentOf="+mainGroup.parentOf(group));System.out.println("parentOf="+mainGroup.parentOf(mainGroup));}}

這里需要特別說明的是setMaxPriority,我們通過分析源碼得出結論,線程的最大優先級,不能高于所在線程組的最大優先級,但是如果我們把代碼寫成下面這樣會怎么樣呢?

ThreadGroup的其他方法

ThreadGroup的interrupt

interrupt一個thread group會導致該group中所有的active線程都被interrupt,也就是說該group中每一個線程的interrupt標識都被設置了

ThreadGroup的destroy
destroy用于銷毀ThreadGroup,該方法只是針對一個沒有任何active線程的group進行一次destroy標記,調用該方法的直接結果是在父group中將自己移除:

鉤子線程

JVM進程的退出是由于JVM進程中沒有活躍的非守護線程,或者收到了系統中斷信號,向JVM程序注入一個Hook線程,在JVM進程退出的時候,Hook線程會啟動執行,通過Runtime可以為JVM注入多個Hook線程,下面就通過一個簡單的例子來看一下如何向Java程序注入Hook線程。

ThreadHook.java package com.wangwenjun.concurrent.chapter07;import java.util.concurrent.TimeUnit;public class ThreadHook {public static void main(String[] args){//為應用程序注入鉤子線程Runtime.getRuntime().addShutdownHook(new Thread(){@Overridepublic void run(){try{System.out.println("The hook thread 1 is running.");TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e){e.printStackTrace();}System.out.println("The hook thread 1 will exit.");}});//鉤子線程可注冊多個Runtime.getRuntime().addShutdownHook(new Thread(){@Overridepublic void run(){try{System.out.println("The hook thread 2 is running.");TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e){e.printStackTrace();}System.out.println("The hook thread 2 will exit.");}});System.out.println("The program will is stopping.");} }

在上面代碼中,給Java程序注入了兩個Hook線程,在main線程中結束,也就是JVM中沒有了活動的非守護線程,JVM進程即將退出時,兩個Hook線程會被啟動并且運行,輸出結果如下:

在我們的開發中經常會遇到Hook線程,比如為了防止某個程序被重復啟動,在進程啟動時會創建一個lock文件,進程收到中斷信號的時候會刪除這個lock文件,我們在mysql服務器、zookeeper、kafka等系統中都能看到lock文件的存在,本節中,將利用hook線程的特點,模擬一個防止重復啟動的程序,

用hook線程模擬防重復啟動程序

package com.wangwenjun.concurrent.chapter07;import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.attribute.PosixFilePermission; import java.nio.file.attribute.PosixFilePermissions; import java.util.Set; import java.util.concurrent.TimeUnit;public class PreventDuplicated {private final static String LOCK_PATH = "/home/wangwenjun/locks/";private final static String LOCK_FILE = ".lock";private final static String PERMISSIONS = "rw-------";public static void main(String[] args) throws IOException {//① 注入Hook線程,在程序退出時刪除lock文件Runtime.getRuntime().addShutdownHook(new Thread(() ->{System.out.println("The program received kill SIGNAL.");getLockFile().toFile().delete();}));//② 檢查是否存在.lock文件checkRunning();//③ 簡單模擬當前程序正在運行for (; ; ){try{TimeUnit.MILLISECONDS.sleep(1);System.out.println("program is running.");} catch (InterruptedException e){e.printStackTrace();}}}private static void checkRunning() throws IOException{Path path = getLockFile();if (path.toFile().exists())throw new RuntimeException("The program already running.");Set<PosixFilePermission> perms = PosixFilePermissions.fromString(PERMISS-IONS);Files.createFile(path, PosixFilePermissions.asFileAttribute(perms));}private static Path getLockFile(){return Paths.get(LOCK_PATH, LOCK_FILE);} }

運行上面的程序,會發現在/home/wangwenjun/locks目錄下多了一個.lock文件,程序運行則會創建.lock文件以防止重復啟動
執行kill pid或者kill-1 pid命令之后,JVM進程會收到中斷信號,并且啟動hook線程刪除.lock文件。

Hook線程是一個非常好的機制,可以幫助程序獲得進程中斷信號,有機會在進程退出之前做一些資源釋放的動作,或者做一些告警通知。切記如果強制殺死進程,那么進程將不會收到任何中斷信號。

注:筆記來自書籍《java高并發編程詳解》

總結

以上是生活随笔為你收集整理的【java读书笔记】ThreadGroup和钩子线程的使用的全部內容,希望文章能夠幫你解決所遇到的問題。

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