010-ThreadGroup线程组
線程組ThreadGroup表示一組線程的集合,一旦一個線程歸屬到一個線程組之中后,就不能再更換其所在的線程組。那么為什么要使用線程組呢?個人認為有以下的好處:方便統(tǒng)一管理,線程組可以進行復(fù)制,快速定位到一個線程,統(tǒng)一進行異常設(shè)置等。ThreadGroup它其實并不屬于Java并發(fā)包中的內(nèi)容,它是java.lang中的內(nèi)容。但是掌握對其的于理解,在實際應(yīng)用中有很大的幫助。
一、基本方法
1、獲取當前線程組名
Thread.currentThread().getThreadGroup().getName()2、將線程放入到一個線程組中去
ThreadGroup threadGroup1 = new ThreadGroup("group1");
ThreadGroup threadGroup2 = new ThreadGroup("group2");
Thread thread1 =new Thread(threadGroup1, "group1's member");
Thread thread2 =new Thread(threadGroup2, "group2's member");
其中Thread中和ThreadGroup相關(guān)的構(gòu)造函數(shù):
public Thread(ThreadGroup group, Runnable target) {init(group, target, "Thread-" + nextThreadNum(), 0);}public Thread(ThreadGroup group, String name) {init(group, null, name, 0);}public Thread(ThreadGroup group, Runnable target, String name) {init(group, target, name, 0);}public Thread(ThreadGroup group, Runnable target, String name,long stackSize) {init(group, target, name, stackSize);} View Code它們最終都是調(diào)用同一個函數(shù):
private void init(ThreadGroup g, Runnable target, String name,long stackSize) {Thread parent = currentThread();SecurityManager security = System.getSecurityManager();if (g == null) {//安全檢查if (security != null) {g = security.getThreadGroup();}//設(shè)置線程組if (g == null) {g = parent.getThreadGroup();}}//檢查可達性 g.checkAccess();//是否有權(quán)限訪問if (security != null) {if (isCCLOverridden(getClass())) {security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);}}//往線程組添加線程但未啟動 g.addUnstarted();this.group = g;this.daemon = parent.isDaemon();//是否守護線程this.priority = parent.getPriority();//優(yōu)先級this.name = name.toCharArray();if (security == null || isCCLOverridden(parent.getClass()))this.contextClassLoader = parent.getContextClassLoader();elsethis.contextClassLoader = parent.contextClassLoader;this.inheritedAccessControlContext = AccessController.getContext();this.target = target;setPriority(priority);if (parent.inheritableThreadLocals != null)this.inheritableThreadLocals =ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);this.stackSize = stackSize;tid = nextThreadID();this.me = this;} View Code3、復(fù)制線程組:
//這樣可以復(fù)制group里面的thread信息 Thread[] threads = new Thread[threadGroup.activeCount()]; threadGroup.enumerate(threads);這里的activeCount很明顯就是取得活動的線程,注意。默認情況 下,連同其子線程組也會進行復(fù)制。
4、未捕獲異常處理
ThreadGroup中有一個uncaughtException()方法。當線程組中某個線程發(fā)生Unchecked exception異常時,由執(zhí)行環(huán)境調(diào)用此方法進行相關(guān)處理,如果有必要,可以重新定義此方法
二、應(yīng)用實例
1、基礎(chǔ)示例
package com.lhx.common.thread;import java.util.Date; import java.util.Random; import java.util.concurrent.TimeUnit;class Result {private String name;public String getName() {return name;}public void setName(String name) {this.name = name;}}public class SearchTask implements Runnable {public SearchTask(Result result) {this.result = result;}private Result result;@Overridepublic void run() {String name = Thread.currentThread().getName();System.out.println("Thread Start " + name);try {doTask();result.setName(name);} catch (InterruptedException e) {System.out.printf("Thread %s: Interrupted\n", name);return;}System.out.printf("%s :Thread end %s\n" ,new Date(),name);}private void doTask() throws InterruptedException {Random random = new Random((new Date()).getTime());int value = (int) (random.nextDouble() * 100);System.out.printf("%s :Thread %s: %d\n",new Date(), Thread.currentThread().getName(),value);TimeUnit.SECONDS.sleep(value);}public static void main(String[] args) {System.out.println("main thread start:");//創(chuàng)建5個線程,并入group里面進行管理ThreadGroup threadGroup = new ThreadGroup("Searcher");Result result = new Result();SearchTask searchTask = new SearchTask(result);for (int i = 0; i < 5; i++) {Thread thred = new Thread(threadGroup, searchTask);thred.start();try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}}//通過這種方法可以看group里面的所有信息System.out.printf("Number of Threads: %d\n", threadGroup.activeCount());System.out.printf("Information about the Thread Group\n");threadGroup.list();//這樣可以復(fù)制group里面的thread信息Thread[] threads = new Thread[threadGroup.activeCount()];threadGroup.enumerate(threads);for (int i = 0; i < threadGroup.activeCount(); i++) {System.out.printf("%s:Thread %s: %s\n",new Date(), threads[i].getName(),threads[i].getState());}waitFinish(threadGroup);//將group里面的所有線程都給interpet threadGroup.interrupt();System.out.println("main thread end:");}private static void waitFinish(ThreadGroup threadGroup) {while (threadGroup.activeCount() > 0) {try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}}}} View Code輸出:
main thread start: Thread Start Thread-0 Thu Sep 28 21:45:32 CST 2017 :Thread Thread-0: 42 Thread Start Thread-1 Thu Sep 28 21:45:33 CST 2017 :Thread Thread-1: 31 Thread Start Thread-2 Thu Sep 28 21:45:34 CST 2017 :Thread Thread-2: 12 Thread Start Thread-3 Thu Sep 28 21:45:35 CST 2017 :Thread Thread-3: 3 Thread Start Thread-4 Thu Sep 28 21:45:36 CST 2017 :Thread Thread-4: 30 Number of Threads: 5 Information about the Thread Group java.lang.ThreadGroup[name=Searcher,maxpri=10]Thread[Thread-0,5,Searcher]Thread[Thread-1,5,Searcher]Thread[Thread-2,5,Searcher]Thread[Thread-3,5,Searcher]Thread[Thread-4,5,Searcher] Thu Sep 28 21:45:37 CST 2017:Thread Thread-0: TIMED_WAITING Thu Sep 28 21:45:37 CST 2017:Thread Thread-1: TIMED_WAITING Thu Sep 28 21:45:37 CST 2017:Thread Thread-2: TIMED_WAITING Thu Sep 28 21:45:37 CST 2017:Thread Thread-3: TIMED_WAITING Thu Sep 28 21:45:37 CST 2017:Thread Thread-4: TIMED_WAITING Thu Sep 28 21:45:38 CST 2017 :Thread end Thread-3 Thu Sep 28 21:45:46 CST 2017 :Thread end Thread-2 Thu Sep 28 21:46:04 CST 2017 :Thread end Thread-1 Thu Sep 28 21:46:06 CST 2017 :Thread end Thread-4 Thu Sep 28 21:46:14 CST 2017 :Thread end Thread-0 main thread end:2、統(tǒng)一異常處理實例
package com.lhx.common.thread;public class ThreadGroupException {public static void main(String[] args) {ThreadGroup threadGroup1 =// 這是匿名類寫法new ThreadGroup("group1") {// 繼承ThreadGroup并重新定義以下方法// 在線程成員拋出unchecked exception// 會執(zhí)行此方法public void uncaughtException(Thread t, Throwable e) {System.out.println(t.getName() + ": " + e.getMessage());}};// 這是匿名類寫法Thread thread1 =// 這個線程是threadGroup1的一員new Thread(threadGroup1, new Runnable() {public void run() {// 拋出unchecked異常throw new RuntimeException("測試異常");}});thread1.start();} } View Code輸出
Thread-0: 測試異常三、源碼解讀
1、首先看其包含的變量
public class ThreadGroup implements Thread.UncaughtExceptionHandler { private final ThreadGroup parent;//父親ThreadGroup String name;//ThreadGroup 的名稱 int maxPriority;//線程最大優(yōu)先級 boolean destroyed;//是否被銷毀 boolean daemon;//是否守護線程 boolean vmAllowSuspension;//是否可以中斷 int nUnstartedThreads = 0;//還未啟動的線程 int nthreads;//ThreadGroup中線程數(shù)目 Thread threads[];//ThreadGroup中的線程 int ngroups;//線程組數(shù)目 ThreadGroup groups[];//線程組數(shù)組說明:
(1)線程組也可以包含其他線程組。如上面的groups[].
(2)線程組構(gòu)成一棵樹,在樹中,除了初始線程組外,每個線程組都有一個父線程組
2、構(gòu)造函數(shù)
//私有構(gòu)造函數(shù) private ThreadGroup() { this.name = "system"; this.maxPriority = Thread.MAX_PRIORITY; this.parent = null; } //默認是以當前ThreadGroup傳入作為parent ThreadGroup,新線程組的父線程組是目前正在運行線程的線程組。 public ThreadGroup(String name) { this(Thread.currentThread().getThreadGroup(), name); } //構(gòu)造函數(shù) public ThreadGroup(ThreadGroup parent, String name) { this(checkParentAccess(parent), parent, name); } //私有構(gòu)造函數(shù) private ThreadGroup(Void unused, ThreadGroup parent, String name) { this.name = name; this.maxPriority = parent.maxPriority; this.daemon = parent.daemon; this.vmAllowSuspension = parent.vmAllowSuspension; this.parent = parent; parent.add(this); }其終的調(diào)用構(gòu)造函數(shù)只有一個,父線程組的 checkAccess 方法在checkParentAccess中會調(diào)用:
//檢查parent ThreadGroup private static void checkParentAccess(ThreadGroup parent) { parent.checkAccess(); return null; }未捕獲異常設(shè)置:
public void uncaughtException(Thread t, Throwable e) {if (parent != null) {parent.uncaughtException(t, e);//父線程組不為空,設(shè)置到父線程組 } else {Thread.UncaughtExceptionHandler ueh = Thread.getDefaultUncaughtExceptionHandler();if (ueh != null) {ueh.uncaughtException(t, e);} else if (!(e instanceof ThreadDeath)) {System.err.print("Exception in thread \"" + t.getName() + "\" ");e.printStackTrace(System.err);}}}如果父線程組存在, 則調(diào)用它的uncaughtException方法.
如果父線程組不存在, 但指定了默認處理器 (下節(jié)中的As the default handler for the application), 則調(diào)用默認的處理器
如果默認處理器沒有設(shè)置, 則寫錯誤日志.但如果 exception是ThreadDeath實例的話, 忽略
3、線程組復(fù)制:
//此線程組及其子組中的所有活動線程復(fù)制到指定數(shù)組中。 public int enumerate(ThreadGroup list[]) {checkAccess();return enumerate(list, 0, true);}//此線程組及其子組中的所有活動線程復(fù)制到指定數(shù)組中。 public int enumerate(ThreadGroup list[], boolean recurse) {checkAccess();return enumerate(list, 0, recurse);}//此線程組中的所有活動線程復(fù)制到指定數(shù)組中。如果 recurse 標志為 true,則還包括對此線程的子組中的所有活動線程的引用。如果數(shù)組太小而無法保持所有線程,則 // 忽略額外的線程。 private int enumerate(ThreadGroup list[], int n, boolean recurse) {int ngroupsSnapshot = 0;ThreadGroup[] groupsSnapshot = null;synchronized (this) {if (destroyed) {return 0;}int ng = ngroups;if (ng > list.length - n) {//防止list放不下線程數(shù)目 ng = list.length - n;}if (ng > 0) {System.arraycopy(groups, 0, list, n, ng);//復(fù)制線程組 n += ng;}if (recurse) { //取得其子組 ngroupsSnapshot = ngroups;if (groups != null) {groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);} else {groupsSnapshot = null;}}}if (recurse) {//復(fù)制子組 for (int i = 0; i < ngroupsSnapshot; i++) {n = groupsSnapshot[i].enumerate(list, n, true);}}return n;} View Code4、其他方法
int activeCount():獲取線程組中活動線程的數(shù)量
interrupt():中斷線程組中所有線程
isDaemon():是否為后臺線程組
setDaemon(boolean daemon):設(shè)置為后臺線程組
setMaxPriority(int pri):設(shè)置線程組的最高優(yōu)先級
四、線程池和線程組區(qū)別
線程組:
1.線程組管理線程,設(shè)置優(yōu)先級,等屬性,安全控制。
2.線程組必須從屬于其他線程組,默認是系統(tǒng)主線程組。
3.將線程加入到線程組需要先創(chuàng)建線程組對象,將其作為線程構(gòu)造函數(shù)參數(shù)。
4.List()輸出線程樹,enumerate()復(fù)制線程組中所有線程到一個線程數(shù)組中
線程組存在的意義,首要原因是安全。java默認創(chuàng)建的線程都是屬于系統(tǒng)線程組,而同一個線程組的線程是可以相互修改對方的數(shù)據(jù)的。但如果在不同的線程組中,那么就不能“跨線程組”修改數(shù)據(jù),可以從一定程度上保證數(shù)據(jù)安全。
線程池:是為了管理線程的生命周期,復(fù)用線程,減少創(chuàng)建銷毀線程的開銷。
線程池存在的意義,首要作用是效率。
線程的創(chuàng)建和結(jié)束都需要耗費一定的系統(tǒng)時間(特別是創(chuàng)建),不停創(chuàng)建和刪除線程會浪費大量的時間。所以,在創(chuàng)建出一條線程并使其在執(zhí)行完任務(wù)后不結(jié)束,而是使其進入休眠狀態(tài),在需要用時再喚醒,那么 就可以節(jié)省一定的時間。
如果這樣的線程比較多,那么就可以使用線程池來進行管理。保證效率。
一般情況下,線程越多占用內(nèi)存也越大,并發(fā)量也越大。
線程組和線程池共有的特點:
1,都是管理一定數(shù)量的線程
2,都可以對線程進行控制---包括休眠,喚醒,結(jié)束,創(chuàng)建,中斷(暫停)--但并不一定包含全部這些操作。
?
總結(jié)
以上是生活随笔為你收集整理的010-ThreadGroup线程组的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: requests基础3
- 下一篇: 王吉伟:厉害了王坚的《在线》 未来世界还