我們的項目用到了ThreadGroup 把thread放到了threadGroup中,名稱統一起來了;
private static final ExecutorService EXECUTOR_SERVICE = new ThreadPoolExecutor(16, 32, 5L, TimeUnit.MINUTES, new ArrayBlockingQueue<>(1000), new ThreadFactory() { private final ThreadGroup threadGroup = new ThreadGroup("fileTemplateMethodThreadGroup"); private final AtomicInteger threadNumber = new AtomicInteger(1); @Override public Thread newThread(Runnable r) { return new Thread(threadGroup, r, "fileTemplateMethod-thread-pool-" + threadNumber.getAndIncrement()); } }, (r, executor) -> { if (!executor.isShutdown()) { /* 丟棄隊列最老的數據 */ if (executor.getQueue().poll() != null) { Cat.logMetricForCount(CatConstant.METRIC_DISCARD_FILE_TASK_COUNT); } executor.execute(r); } });
ThreadGroup 可以把thread的名字統一起來。一起處理catch。
ThreadGroup是Java提供的一種對線程進行分組管理的手段,可以對所有線程以組為單位進行操作,如設置優先級、守護線程等。
線程組也有父子的概念,如下圖:
線程組的創建
public class ThreadGroupCreator { public static void main(String[] args) { //獲取當前線程的group ThreadGroup currentGroup = Thread.currentThread().getThreadGroup(); //在當前線程執行流中新建一個Group1 ThreadGroup group1 = new ThreadGroup("Group1"); //Group1的父線程,就是main線程所在Group System.out.println(group1.getParent() == currentGroup); //定義Group2, 指定group1為其父線程 ThreadGroup group2 = new ThreadGroup(group1, "Group2"); System.out.println(group2.getParent() == group1); } }
ThreadGroup是位於java.lang包下的一個類,用於統一的線程管理.一旦一個線程加入到一個線程組后,就不能更換線程所在的線程組
將當前線程加入到線程組中
public class ThreadGroupCreator { public static void main(String[] args) { //獲取當前線程的group ThreadGroup currentGroup = Thread.currentThread().getThreadGroup(); //在當前線程執行流中新建一個Group1 ThreadGroup group1 = new ThreadGroup("Group1"); //Group1的父線程,就是main線程所在Group System.out.println(group1.getParent() == currentGroup); //定義Group2, 指定group1為其父線程 ThreadGroup group2 = new ThreadGroup(group1, "Group2"); System.out.println(group2.getParent() == group1); } }
將ThreadGroup中活躍的線程引用復制到線程組
Thread[] threads = new Thread[num]; threadGroup.enumerate(threads); for (Thread t : threads) { System.out.println("線程名-" + t.getName()); }
測試源代碼如下
public class MyThread implements Runnable { @Override public void run() { try { System.out.println(Thread.currentThread().getName() + " -> start"); TimeUnit.SECONDS.sleep(10); //隨機發生異常 if (ThreadLocalRandom.current().nextInt(10) > 5) { throw new RuntimeException(Thread.currentThread().getName() + "發生異常"); } System.out.println(Thread.currentThread().getName() + " -> end"); } catch (InterruptedException e) { e.printStackTrace(); } }
public class ThreadGroupTest { public static void main(String[] args) { int num = 10; ThreadGroup threadGroup = new ThreadGroup("test-group") { @Override public void uncaughtException(Thread t, Throwable e) { System.out.println("ThreadGroup捕獲到線程異常 - " + e.getMessage()); } }; List<Thread> threadList = new ArrayList<>(); for (int i = 0; i < num; i++) { Thread thread = new Thread(threadGroup, new MyThread(), "threadname-" + i); threadList.add(thread); } System.out.println("運行前線程組中活躍線程數 -> " + threadGroup.activeCount()); System.out.println("開始運行所有線程..."); for (Thread t : threadList) { t.start(); } //獲取線程組中所有[活動]線程 Thread[] threads = new Thread[num]; threadGroup.enumerate(threads); for (Thread t : threads) { System.out.println("線程名-" + t.getName()); } System.out.println("所有線程運行后,線程組中活躍線程數-" + threadGroup.activeCount()); //不斷的查看線程組中活躍的線程數 Thread thread = new Thread(() -> { int num1; try { while ((num1 = threadGroup.activeCount()) > 0) { System.out.println("當前線程組活躍線程數為 -> " + num1); TimeUnit.SECONDS.sleep(1); } System.out.println("All Thread HAS FINISHED"); } catch (InterruptedException e) { e.printStackTrace(); } }); thread.start(); } }
運行結果如下
運行前線程組中活躍線程數 -> 0
開始運行所有線程...
threadname-0 -> start threadname-1 -> start threadname-2 -> start threadname-3 -> start threadname-4 -> start threadname-5 -> start threadname-6 -> start threadname-7 -> start threadname-8 -> start 線程名-threadname-0 threadname-9 -> start 線程名-threadname-1 線程名-threadname-2 線程名-threadname-3 線程名-threadname-4 線程名-threadname-5 線程名-threadname-6 線程名-threadname-7 線程名-threadname-8 線程名-threadname-9 所有線程運行后,線程組中活躍線程數-10 當前線程組活躍線程數為 -> 10 當前線程組活躍線程數為 -> 10 當前線程組活躍線程數為 -> 10 當前線程組活躍線程數為 -> 10 當前線程組活躍線程數為 -> 10 當前線程組活躍線程數為 -> 10 當前線程組活躍線程數為 -> 10 當前線程組活躍線程數為 -> 10 當前線程組活躍線程數為 -> 10 當前線程組活躍線程數為 -> 10 threadname-5 -> end threadname-8 -> end ThreadGroup捕獲到線程異常 - threadname-7發生異常 ThreadGroup捕獲到線程異常 - threadname-2發生異常 threadname-4 -> end ThreadGroup捕獲到線程異常 - threadname-3發生異常 ThreadGroup捕獲到線程異常 - threadname-9發生異常 ThreadGroup捕獲到線程異常 - threadname-1發生異常 threadname-6 -> end threadname-0 -> end All Thread HAS FINISHED ---------------------
線程組的基本操作
注意:后添加進線程組的線程,其優先級不能大於線程組的優先級
public class ThreadGroupBasic { public static void main(String[] args) throws InterruptedException { 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(); TimeUnit.MILLISECONDS.sleep(1); ThreadGroup mainGroup = Thread.currentThread().getThreadGroup(); //遞歸獲取mainGroup中活躍線程的估計值 System.out.println("activeCount = " + mainGroup.activeCount()); //遞歸獲mainGroup中的活躍子group System.out.println("activeGroupCount = " + mainGroup.activeGroupCount()); //獲取group的優先級, 默認為10 System.out.println("getMaxPriority = " + mainGroup.getMaxPriority()); //獲取group的名字 System.out.println("getName = " + mainGroup.getName()); //獲取group的父group, 如不存在則返回null System.out.println("getParent = " + mainGroup.getParent()); //活躍線程信息全部輸出到控制台 mainGroup.list(); System.out.println("----------------------------"); //判斷當前group是不是給定group的父線程, 如果兩者一樣,也會返回true System.out.println("parentOf = " + mainGroup.parentOf(group)); System.out.println("parentOf = " + mainGroup.parentOf(mainGroup)); } }
線程組的Interrupt
public class ThreadGroupInterrupt { public static void main(String[] args) throws InterruptedException { ThreadGroup group = new ThreadGroup("TestGroup"); new Thread(group, () -> { while(true) { try { TimeUnit.MILLISECONDS.sleep(2); } catch (InterruptedException e) { //received interrupt signal and clear quickly System.out.println(Thread.currentThread().isInterrupted()); break; } } System.out.println("t1 will exit"); }, "t1").start(); new Thread(group, () -> { while(true) { try { TimeUnit.MILLISECONDS.sleep(2); } catch (InterruptedException e) { //received interrupt signal and clear quickly System.out.println(Thread.currentThread().isInterrupted()); break; } } System.out.println("t2 will exit"); }, "t2").start(); //make sure all threads start TimeUnit.MILLISECONDS.sleep(2); group.interrupt(); } }
線程組的destroy
public class ThreadGroupDestroy { public static void main(String[] args) { ThreadGroup group = new ThreadGroup("TestGroup"); ThreadGroup mainGroup = Thread.currentThread().getThreadGroup(); //before destroy System.out.println("group.isDestroyed=" + group.isDestroyed()); mainGroup.list(); group.destroy(); //after destroy System.out.println("group.isDestroyed=" + group.isDestroyed()); mainGroup.list(); } }
線程組設置守護線程組
線程組設置為守護線程組,並不會影響其線程是否為守護線程,僅僅表示當它內部沒有active的線程的時候,會自動destroy
public class ThreadGroupDaemon { public static void main(String[] args) throws InterruptedException { ThreadGroup group1 = new ThreadGroup("group1"); new Thread(group1, () -> { try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } }, "group1-thread1").start(); ThreadGroup group2 = new ThreadGroup("group2"); new Thread(group2, () -> { try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } }, "group1-thread2").start(); group2.setDaemon(true); TimeUnit.SECONDS.sleep(3); System.out.println(group1.isDestroyed()); System.out.println(group2.isDestroyed()); } }
參考:
ThreadGroup解讀