java ThreadGroup源码分析

使用:

《java ThreadGroup源码分析》
《java ThreadGroup源码分析》

 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 }

View Code

一、构造函数

  两种构造函数:

ThreadGroup(String name) 
         
ThreadGroup(ThreadGroup parent, String name) 

  

// 创建一个线程组必须关联到一个父线程组,默认父线程组是当前线程的线程组Thread.currentThread().getThreadGroup()。
// 并检查父线程组的权限。
《java ThreadGroup源码分析》
《java ThreadGroup源码分析》

public ThreadGroup(String name) {
    this(Thread.currentThread().getThreadGroup(), name);
}

View Code
《java ThreadGroup源码分析》
《java ThreadGroup源码分析》

1 public ThreadGroup(ThreadGroup parent, String name) {
2     this(checkParentAccess(parent), parent, name);
3 }

View Code
// 初始化此线程组的名称(name)、最高优先级(maxPriority)、daemon、父线程组(parent)
// 并将此线程组添加到父线程组中(parent.add(this))
《java ThreadGroup源码分析》
《java ThreadGroup源码分析》

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 }

View Code
// 添加一个线程组到此线程组
《java ThreadGroup源码分析》
《java ThreadGroup源码分析》

 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 }

View Code

 二、添加线程到线程组

《java ThreadGroup源码分析》
《java ThreadGroup源码分析》

1 ThreadGroup tg = new ThreadGroup("threadGroup-001"); 
2 Thread t1 = new Thread(tg, new MyThread());
3 t1.start();

View Code

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) 。

源码如下:

《java ThreadGroup源码分析》
《java ThreadGroup源码分析》

 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     }

View Code
《java ThreadGroup源码分析》
《java ThreadGroup源码分析》

1 void threadStartFailed(Thread t) {
2         synchronized(this) {
3             // 线程组中移除线程t
4             remove(t);
5             // 未启动线程数增加1
6             nUnstartedThreads++;
7         }
8     }

View Code
《java ThreadGroup源码分析》
《java ThreadGroup源码分析》

 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     }

View Code

由上可见:只有调用start()成功启动的线程才会被它的线程组保存。

 

三、ThreadGroup的一些函数

1、destory() 销毁此线程组及其所有子组

《java ThreadGroup源码分析》
《java ThreadGroup源码分析》

 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     }

View Code

2、interrupt() 中断此线程组中的所有线程(包括子线程组中的线程)

《java ThreadGroup源码分析》
《java ThreadGroup源码分析》

 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     }

View Code

3、setMaxPriority 设置线程组(包括子线程组)的最高优先级

《java ThreadGroup源码分析》
《java ThreadGroup源码分析》

 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     }

View Code

4、parentOf 判断是否为当前线程组的祖先线程组(或是否是当前线程组)

《java ThreadGroup源码分析》
《java ThreadGroup源码分析》

 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     }

View Code

5、activeCount 返回线程组中活动线程的估计数

《java ThreadGroup源码分析》
《java ThreadGroup源码分析》

 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     }

View Code

6、activeGroupCount 返回此线程组中活动线程组的估计数

《java ThreadGroup源码分析》
《java ThreadGroup源码分析》

 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     }

View Code

7、enumerate 所有活动线程复制到指定数组中

《java ThreadGroup源码分析》
《java ThreadGroup源码分析》

 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     }

View Code

 

    原文作者:那天ws
    原文地址: https://www.cnblogs.com/natian-ws/p/10195184.html
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞