zoukankan      html  css  js  c++  java
  • 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()。
    // 并检查父线程组的权限。
    public ThreadGroup(String name) {
        this(Thread.currentThread().getThreadGroup(), name);
    }
    View Code
    1 public ThreadGroup(ThreadGroup parent, String name) {
    2     this(checkParentAccess(parent), parent, name);
    3 }
    View Code
    // 初始化此线程组的名称(name)、最高优先级(maxPriority)、daemon、父线程组(parent)
    // 并将此线程组添加到父线程组中(parent.add(this))
    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
    // 添加一个线程组到此线程组
     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

     二、添加线程到线程组

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

    源码如下:

     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
    1 void threadStartFailed(Thread t) {
    2         synchronized(this) {
    3             // 线程组中移除线程t
    4             remove(t);
    5             // 未启动线程数增加1
    6             nUnstartedThreads++;
    7         }
    8     }
    View Code
     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() 销毁此线程组及其所有子组

     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() 中断此线程组中的所有线程(包括子线程组中的线程)

     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 设置线程组(包括子线程组)的最高优先级

     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 判断是否为当前线程组的祖先线程组(或是否是当前线程组)

     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 返回线程组中活动线程的估计数

     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 返回此线程组中活动线程组的估计数

     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 所有活动线程复制到指定数组中

     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
  • 相关阅读:
    Cousera课程Learning How to Learn学习报告
    C语言中当无符号数遇到符号数
    STC15 串口(工作方式1)使用小结
    取C语言头文件的文件名
    linux 的 shell 逻辑
    Win7 局域网内简单共享的设置
    写了一个批处理,可以实现文件备份,自动对比删除冗余文件。
    C语言 函数指针的应用
    自动控制原理 典型环节频率特性对比
    51单片机汇编的溢出标志位OV和进位标志位CY
  • 原文地址:https://www.cnblogs.com/natian-ws/p/10195184.html
Copyright © 2011-2022 走看看