執行緒管理
1.執行緒組
類似於電腦中,使用文件夾管理文件,也可以使用執行緒組來管理執行緒,在執行緒組中定義一組相似的執行緒,在在執行緒組中也可以定義子執行緒組。
Thread類有幾個構造方法允許在創建執行緒時指定執行緒組,如果在創建執行緒時沒有指定執行緒組,則該執行緒就屬於父執行緒所在的執行緒組,JVM在創建main執行緒時會為它指定一個執行緒組,因此每個java執行緒都有一個執行緒組與之相關,可以調用getThreadGroup()返回執行緒組嗎。
1.1返回當前main的執行緒組
public class ThreadGroupText {
public static void main(String[] args) {
ThreadGroup threadGroup=Thread.currentThread().getThreadGroup();
System.out.println(threadGroup);
}
}
1.2 定義執行緒組,如果不指定執行緒組,則自動歸為當前所屬的執行緒
public class ThreadGroupText {
public static void main(String[] args) {
ThreadGroup threadGroup1=new ThreadGroup("group1");
System.out.println(threadGroup1);
}
}
1.3 定義執行緒組同時指定父執行緒
public class ThreadGroupText {
public static void main(String[] args) {
ThreadGroup threadGroup=Thread.currentThread().getThreadGroup();
System.out.println(threadGroup);
ThreadGroup threadGroup1=new ThreadGroup("group1");
System.out.println(threadGroup1.getParent());
ThreadGroup threadGroup2=new ThreadGroup(threadGroup,"group2");
System.out.println("threadGroup1-->"+threadGroup1.getParent());
System.out.println("threadGroup2-->"+threadGroup2.getParent());
}
}
1.4創建執行緒時指定所屬執行緒組
public class ThreadGroupText {
public static void main(String[] args) {
Runnable r=new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread());
}
};
Thread t1=new Thread(r,"t1");
System.out.println(t1);
}
}
Thread[t1,5,main]//執行緒名稱 優先順序 父執行緒組
在main執行緒中創建了t1執行緒,main為父執行緒,t1為子執行緒,t1沒有指定執行緒組t1就屬於父執行緒組。
1.5執行緒組的基本操作
activecount()返回當前執行緒組及子執行緒組中活動執行緒的數量
activeGroupCount()返回當前執行緒組以及子執行緒組中活動執行緒組的數量
int enumerate(Thread[] list)將當前執行緒組中的活動執行緒複製到參數數組中
enmerate(ThreadGroup[] list) 將當前執行緒組中的活動執行緒複製到參數數組中
getMaxPriority()獲取執行緒組最大優先順序,默認是10
getParent()返回父執行緒組
getName()返回執行緒組的名字
interrup()中斷執行緒組的所有執行緒
IsDaemon()判斷當前執行緒組是否為守護執行緒
list()將當前執行緒組中的活動執行緒列印出來
ParentOf(HtreadGroup g)判斷當前執行緒組是否為參數執行緒組的父執行緒組
setDaemon()設置執行緒組為守護執行緒
2.捕獲執行緒的執行異常
在執行緒Run方法中,如果有受檢異常必須捕獲處理,如果想要獲得Run方法中出現的運行時異常,可以通過回調UncaughtExceptHandler
介面獲得哪個執行緒出現了運行時異常。
2.1.Thread類相關異常處理方法
getdefaultUncaughtExceptHandle
獲得全局的UncaughtExceptHandler
getUncaughtExceptHandler
獲得當前執行緒的UncaughtExceptHandler
setdefaultUncaughtExceptHandle
設置全局的UncaughtExceptHandler
setUncaughtExceptHandler
設置當前執行緒的UncaughtExceptHandler
當執行緒出現異常,JVM會調用Thread類的dispatchcaughtExceptHandler(Throwable e)
方法,該方法會調用
getUncaughtExceptHandler().UncaughtException(this e)
,如果想要獲得異常資訊,就需要設置執行緒的UncaughtExceptHandler
2.2設置執行緒異常的回調介面方法
package com;
public class ThreadExcept{
public static void main(String[] args) {
//設置執行緒全局回調介面
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler(){
@Override
public void uncaughtException(Thread t, Throwable e) {
//t參數接受發生異常的執行緒,e就是該執行緒中的異常資訊
System.out.println(t.getName()+"發生了"+e.getMessage());
}
});
Thread t1=new Thread(new Runnable() {
@Override
public void run() {
String name=null;
System.out.println(name.length());
}
});
t1.start();
}
}
在實際開發中,這種設計異常處理方式還是比較常用的,尤其是異常執行方法
如果執行緒產生異常,JVM會調用dispatchcaughtException
方法,該方法中調用了getUncaughtExceptionHandler().UncaughtException(this e)
;如果當前執行緒設置了UncaughtExceptionHandler
回調介面就直接調用它自己的UncaughtException
方法,如果沒有設置則調用當前執行緒所在執行緒組UncaughtExceptionHandler
回調介面UncaughtException
方法,如果執行緒組也沒有設置回調介面,則直接把異常的棧資訊定向Sysytem.err中。
3.注入Hook鉤子執行緒
很多軟體包括Mysql、Zookeeper、Kafka都存在Hook執行緒的效驗機制,目的就是效驗進程是否已啟動,防止反覆啟動應用程式。
Hook執行緒也叫鉤子執行緒,當JVM退出的時候會執行Hook執行緒,經常在程式啟動的時候創建一個.lock執行緒,用.lock校驗程式是否在啟動,在程式退出時刪除.lock文件,在Hook執行緒中處理防止重複啟動之外還可以做資源釋放,盡量避免在Hook執行緒中做複雜操作。
package com;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
public class HookText {
public static void main(String[] args) throws IOException, InterruptedException {
//注入Hook執行緒,在程式退出時,刪除.lock文件
Runtime.getRuntime().addShutdownHook(new Thread(){
@Override
public void run() {
System.out.println("JVM退出,會啟動當前Hook執行緒,在Hook執行緒中刪除.lock文件");
getFile().toFile().delete();
}
});
//檢查lock文件是否存在
if(getFile().toFile().exists())
{
throw new RuntimeException("程式已啟動");
}
else
{
getFile().toFile().createNewFile();
System.out.println("創建lock文件");
}
for (int i = 0; i < 100; i++) {
System.out.println("程式正在運行");
Thread.sleep(100);
}
}
private static Path getFile()
{
return Paths.get("","tmp.lock");
}
}
當項目已啟動,JVM會在項目文件夾目錄會自動創建一個.lock文件
只有當項目自動運行結束JVM自動退出時會刪除.lock文件,當讓程式運行時停止,.lock文件不會被刪除,再運行會拋出異常