使用:
1 import javax.swing.text.html.HTMLDocument.HTMLReader.IsindexAction; 2 3 public class Test { 4 5 public static void main(String[] args) { 6 7 ThreadGroup tg = new ThreadGroup("threadGroup-001"); 8 9 Thread t1 = new Thread(tg, new MyThread()); 10 t1.start(); 11 12 Thread t2 = new Thread(tg, new MyThread()); 13 t2.start(); 14 15 // 返回线程组中活动线程的估计数 16 System.out.println("active thread group: " + tg.activeCount()); 17 // 返回此线程组中活动线程组的估计数 18 System.out.println("activeGroupCount: " + tg.activeGroupCount()); 19 // 检查当前运行的线程是否有权修改此线程组 20 tg.checkAccess(); 21 // 设置线程组的最高优先级 22 tg.setMaxPriority(6); 23 // 返回此线程组的最高优先级 24 System.out.println("maxPriority: " + tg.getMaxPriority()); 25 // 返回此线程组的名称 26 System.out.println("thread group name: " + tg.getName()); 27 // 返回此线程组的父线程组 28 System.out.println(tg.getParent()); 29 // 中断此线程组中的所有线程 30 tg.interrupt(); 31 // 更改此线程组的后台程序状态 32 tg.setDaemon(true); 33 // 测试此线程组是否为一个后台程序线程组 34 System.out.println("is daemon: " + tg.isDaemon()); 35 // 测试此线程组是否为线程组参数或其祖先线程组之一 36 System.out.println("is parent: "+ tg.getParent().parentOf(tg)); 37 // 打印线程组信息 38 tg.list(); 39 // 返回线程组的字符串表示形式 40 System.out.println(tg.toString()); 41 // 销毁此线程组及其所有子组 42 tg.destroy(); 43 // 测试此线程组是否已经销毁 44 System.out.println(tg.isDestroyed()); 45 // System.out.println(tg.); 46 } 47 48 private static class MyThread extends Thread { 49 @Override 50 public void run() { 51 System.out.println("thread name: " + Thread.currentThread().getName()); 52 } 53 } 54 55 }
一、构造函数
两种构造函数:
ThreadGroup(String name)
ThreadGroup(ThreadGroup parent, String name)
public ThreadGroup(String name) { this(Thread.currentThread().getThreadGroup(), name); }
1 public ThreadGroup(ThreadGroup parent, String name) { 2 this(checkParentAccess(parent), parent, name); 3 }
1 private ThreadGroup(Void unused, ThreadGroup parent, String name) { 2 this.name = name; 3 this.maxPriority = parent.maxPriority; 4 this.daemon = parent.daemon; 5 this.parent = parent; 6 parent.add(this); 7 }
1 private final void add(ThreadGroup g){ 2 synchronized (this) { 3 if (destroyed) { 4 throw new IllegalThreadStateException(); 5 } 6 // 添加一个线程组到此线程组的groups数组中,groups初始容量为4,每次容量耗尽之后按2倍扩增。 7 if (groups == null) { 8 groups = new ThreadGroup[4]; 9 } else if (ngroups == groups.length) { 10 groups = Arrays.copyOf(groups, ngroups * 2); 11 } 12 groups[ngroups] = g; 13 14 // This is done last so it doesn't matter in case the 15 // thread is killed 16 ngroups++; 17 } 18 }
二、添加线程到线程组
1 ThreadGroup tg = new ThreadGroup("threadGroup-001"); 2 Thread t1 = new Thread(tg, new MyThread()); 3 t1.start();
new Thread(tg, new MyThread()); 调用后,关于线程组相关的操作设置可在 private Thread(ThreadGroup g, Runnable target, String name,long stackSize, AccessControlContext acc,boolean inheritThreadLocals)看到:
1 private Thread(ThreadGroup g, Runnable target, String name, 2 long stackSize, AccessControlContext acc, 3 boolean inheritThreadLocals) { 4 if (name == null) { 5 throw new NullPointerException("name cannot be null"); 6 } 7 8 this.name = name; 9 10 Thread parent = currentThread(); 11 SecurityManager security = System.getSecurityManager(); 12 if (g == null) { 13 /* Determine if it's an applet or not */ 14 15 /* If there is a security manager, ask the security manager 16 what to do. */ 17 if (security != null) { 18 g = security.getThreadGroup(); 19 } 20 21 /* If the security manager doesn't have a strong opinion 22 on the matter, use the parent thread group. */ 23 // 此线程没有明确指定线程组时,为其指定当前线程所在的线程组 24 if (g == null) { 25 g = parent.getThreadGroup(); 26 } 27 } 28 29 /* checkAccess regardless of whether or not threadgroup is 30 explicitly passed in. */ 31 g.checkAccess(); 32 33 /* 34 * Do we have the required permissions? 35 */ 36 if (security != null) { 37 if (isCCLOverridden(getClass())) { 38 security.checkPermission( 39 SecurityConstants.SUBCLASS_IMPLEMENTATION_PERMISSION); 40 } 41 } 42 43 // 调用类ThreadGroup的addUnstarted函数, 添加一个未启用的线程到线程组 44 g.addUnstarted(); 45 46 // 设置当前线程的线程组 47 this.group = g; 48 this.daemon = parent.isDaemon(); 49 this.priority = parent.getPriority(); 50 if (security == null || isCCLOverridden(parent.getClass())) 51 this.contextClassLoader = parent.getContextClassLoader(); 52 else 53 this.contextClassLoader = parent.contextClassLoader; 54 this.inheritedAccessControlContext = 55 acc != null ? acc : AccessController.getContext(); 56 this.target = target; 57 setPriority(priority); 58 if (inheritThreadLocals && parent.inheritableThreadLocals != null) 59 this.inheritableThreadLocals = 60 ThreadLocal.createInheritedMap(parent.inheritableThreadLocals); 61 /* Stash the specified stack size in case the VM cares */ 62 this.stackSize = stackSize; 63 64 /* Set thread ID */ 65 this.tid = nextThreadID(); 66 }
主要操作:设置此线程的线程组,将线程组的未启动线程数加1(addUnstarted() 即nUnstartedThreads++)。
随后启动一个线程(t1.start()):
1 public synchronized void start() { 2 /** 3 * This method is not invoked for the main method thread or "system" 4 * group threads created/set up by the VM. Any new functionality added 5 * to this method in the future may have to also be added to the VM. 6 * 7 * A zero status value corresponds to state "NEW". 8 */ 9 if (threadStatus != 0) 10 throw new IllegalThreadStateException(); 11 12 /* Notify the group that this thread is about to be started 13 * so that it can be added to the group's list of threads 14 * and the group's unstarted count can be decremented. */ 15 group.add(this); 16 17 boolean started = false; 18 try { 19 start0(); 20 started = true; 21 } finally { 22 try { 23 if (!started) { 24 group.threadStartFailed(this); 25 } 26 } catch (Throwable ignore) { 27 /* do nothing. If start0 threw a Throwable then 28 it will be passed up the call stack */ 29 } 30 } 31 }
start()中的先调用 group.add(this)。然后线程启动失败后调用 group.threadStartFailed(this) 。
源码如下:
1 void add(Thread t) { 2 synchronized (this) { 3 if (destroyed) { 4 throw new IllegalThreadStateException(); 5 } 6 // ThreadGroup维护了一个数组,用来存放线程。 7 if (threads == null) { 8 threads = new Thread[4]; 9 } else if (nthreads == threads.length) { 10 threads = Arrays.copyOf(threads, nthreads * 2); 11 } 12 // 添加线程到数组中 13 threads[nthreads] = t; 14 15 // This is done last so it doesn't matter in case the 16 // thread is killed 17 // 线程数组中线程数量增加1 18 nthreads++; 19 20 // The thread is now a fully fledged member of the group, even 21 // though it may, or may not, have been started yet. It will prevent 22 // the group from being destroyed so the unstarted Threads count is 23 // decremented. 24 // 未启动线程数减1 25 nUnstartedThreads--; 26 } 27 }
1 void threadStartFailed(Thread t) { 2 synchronized(this) { 3 // 线程组中移除线程t 4 remove(t); 5 // 未启动线程数增加1 6 nUnstartedThreads++; 7 } 8 }
1 private void remove(Thread t) { 2 synchronized (this) { 3 if (destroyed) { 4 return; 5 } 6 // 循环遍历查找线程t,并移除 7 for (int i = 0 ; i < nthreads ; i++) { 8 if (threads[i] == t) { 9 System.arraycopy(threads, i + 1, threads, i, --nthreads - i); 10 // Zap dangling reference to the dead thread so that 11 // the garbage collector will collect it. 12 threads[nthreads] = null; 13 break; 14 } 15 } 16 } 17 }
由上可见:只有调用start()成功启动的线程才会被它的线程组保存。
三、ThreadGroup的一些函数
1、destory() 销毁此线程组及其所有子组
1 // 销毁此线程组及其所有子线程组 2 public final void destroy() { 3 int ngroupsSnapshot; 4 ThreadGroup[] groupsSnapshot; 5 synchronized (this) { 6 checkAccess(); 7 if (destroyed || (nthreads > 0)) { 8 throw new IllegalThreadStateException(); 9 } 10 // 子线程组数量 11 ngroupsSnapshot = ngroups; 12 // 子线程组数组 13 if (groups != null) { 14 groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot); 15 } else { 16 groupsSnapshot = null; 17 } 18 // 置空子线程数量、子线程组、子线程组数量、子线程组数组 19 if (parent != null) { 20 destroyed = true; 21 ngroups = 0; 22 groups = null; 23 nthreads = 0; 24 threads = null; 25 } 26 } 27 // 递归子线程组 28 for (int i = 0 ; i < ngroupsSnapshot ; i += 1) { 29 groupsSnapshot[i].destroy(); 30 } 31 // 从父线程组中移除此线程组 32 if (parent != null) { 33 parent.remove(this); 34 } 35 }
2、interrupt() 中断此线程组中的所有线程(包括子线程组中的线程)
1 // 中断此线程组中的所有线程(包括子线程组中的线程) 2 public final void interrupt() { 3 int ngroupsSnapshot; 4 ThreadGroup[] groupsSnapshot; 5 synchronized (this) { 6 checkAccess(); 7 // 循环遍历线程组中的子线程,中断线程 8 for (int i = 0 ; i < nthreads ; i++) { 9 threads[i].interrupt(); 10 } 11 ngroupsSnapshot = ngroups; 12 if (groups != null) { 13 groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot); 14 } else { 15 groupsSnapshot = null; 16 } 17 } 18 // 递归去子线程组执行interrupt() 19 for (int i = 0 ; i < ngroupsSnapshot ; i++) { 20 groupsSnapshot[i].interrupt(); 21 } 22 }
3、setMaxPriority 设置线程组(包括子线程组)的最高优先级
1 // 设置线程组(包括子线程组)的最高优先级 2 public final void setMaxPriority(int pri) { 3 int ngroupsSnapshot; 4 ThreadGroup[] groupsSnapshot; 5 synchronized (this) { 6 checkAccess(); 7 // 检验优先级大小是否合规 8 if (pri < Thread.MIN_PRIORITY || pri > Thread.MAX_PRIORITY) { 9 return; 10 } 11 // 最高优先级不能大于父线程组 12 maxPriority = (parent != null) ? Math.min(pri, parent.maxPriority) : pri; 13 ngroupsSnapshot = ngroups; 14 if (groups != null) { 15 groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot); 16 } else { 17 groupsSnapshot = null; 18 } 19 } 20 // 递归设置子线程组的最高优先级 21 for (int i = 0 ; i < ngroupsSnapshot ; i++) { 22 groupsSnapshot[i].setMaxPriority(pri); 23 } 24 }
4、parentOf 判断是否为当前线程组的祖先线程组(或是否是当前线程组)
1 // 判断g是否为当前线程组的祖先线程组(或是否是当前线程组) 2 public final boolean parentOf(ThreadGroup g) { 3 // 向上查找父线程组,直到父线程组为空,判断g是否为当前线程组的祖先线程组(或是否是当前线程组) 4 for (; g != null ; g = g.parent) { 5 if (g == this) { 6 return true; 7 } 8 } 9 return false; 10 }
5、activeCount 返回线程组中活动线程的估计数
1 // 返回线程组中活动线程的估计数 2 public int activeCount() { 3 int result; 4 // Snapshot sub-group data so we don't hold this lock 5 // while our children are computing. 6 int ngroupsSnapshot; 7 ThreadGroup[] groupsSnapshot; 8 synchronized (this) { 9 if (destroyed) { 10 return 0; 11 } 12 // 线程组中的线程数 13 result = nthreads; 14 // 子线程组 15 ngroupsSnapshot = ngroups; 16 if (groups != null) { 17 groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot); 18 } else { 19 groupsSnapshot = null; 20 } 21 } 22 // 递归子孙线程组 23 for (int i = 0 ; i < ngroupsSnapshot ; i++) { 24 result += groupsSnapshot[i].activeCount(); 25 } 26 return result; 27 }
6、activeGroupCount 返回此线程组中活动线程组的估计数
1 public int activeGroupCount() { 2 int ngroupsSnapshot; 3 ThreadGroup[] groupsSnapshot; 4 synchronized (this) { 5 if (destroyed) { 6 return 0; 7 } 8 // 子线程组数量 9 ngroupsSnapshot = ngroups; 10 if (groups != null) { 11 groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot); 12 } else { 13 groupsSnapshot = null; 14 } 15 } 16 int n = ngroupsSnapshot; 17 // 递归子孙线程组 18 for (int i = 0 ; i < ngroupsSnapshot ; i++) { 19 n += groupsSnapshot[i].activeGroupCount(); 20 } 21 return n; 22 }
7、enumerate 所有活动线程复制到指定数组中
1 // rescurse 否还包括作为此线程组的子组的线程组中的线程。 2 // n 是list中已经存在的元素(线程)数量 3 private int enumerate(Thread list[], int n, boolean recurse) { 4 int ngroupsSnapshot = 0; 5 ThreadGroup[] groupsSnapshot = null; 6 synchronized (this) { 7 if (destroyed) { 8 return 0; 9 } 10 // 线程组中的线程 11 int nt = nthreads; 12 // nt不能大于list的可用长度(递归遍历子孙线程组的时候,会带上n,所以此处要减去n) 13 if (nt > list.length - n) { 14 nt = list.length - n; 15 } 16 for (int i = 0; i < nt; i++) { 17 if (threads[i].isAlive()) { 18 list[n++] = threads[i]; 19 } 20 } 21 // 子孙线程组 22 if (recurse) { 23 ngroupsSnapshot = ngroups; 24 if (groups != null) { 25 groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot); 26 } else { 27 groupsSnapshot = null; 28 } 29 } 30 } 31 // 递归子孙线程组 32 if (recurse) { 33 for (int i = 0 ; i < ngroupsSnapshot ; i++) { 34 n = groupsSnapshot[i].enumerate(list, n, true); 35 } 36 } 37 // 返回已添加到list的线程数量 38 return n; 39 }