JDK8中ThreadGroup源码解析

来源:互联网 发布:知乎手机端发表文章 编辑:程序博客网 时间:2024/05/21 22:28
许多线程聚集成组即线程组,线程组可以包括其它线程组,线程组随着层级的增加可形成树,其中的每个线程组除了初始化线程组外都存在着父线程组。线程允许访问关于它自己的线程组的信息,但不允许访问其线程组的父线程组或任何其它线程组的信息。当需要锁定策略的时候,线程组成子线程组到父线程组是尽可能地锁定一个级别的树,但是不锁住树的底部。这样可以限制需要持有的锁的数量,特别是避免为根线程组(或全局锁)获取锁,这锁将是多处理器系统中许多线程组争用的资源。这样的锁定策略通常会导致获取一个线程组状态的快照,并在该快照中工作,而不是在执行的时候将线程组锁住。
 
1.ThreadGroup初始化
ThreadGroup有提供构造方法,可以自行进行初始化设置或者自行交给Thread处理,因为在new Thread()时会默认初始化线程组ThreadGroup。
 
2.ThreadGroup源码解析
public class ThreadGroup implements Thread.UncaughtExceptionHandler {
  private final ThreadGroup parent; // 父线程组 
  String name; // 线程组名称
  int maxPriority; // 线程组优先级
  boolean destroyed; // 是否已经被销毁
  boolean daemon; // 守护线程
  boolean vmAllowSuspension; // 供VM使用
 
  int nUnstartedThreads = 0; // 线程组中未启动的线程
  int nthreads; // 线程数量
  Thread threads[]; // 线程
 
  int ngroups; // 线程组数量
  ThreadGroup groups[]; // 线程组
 
  // 创建系统线程组,不在任何线程组中的空线程组
  private ThreadGroup() {    // called from C code
    this.name = "system";
    this.maxPriority = Thread.MAX_PRIORITY;
    this.parent = null;
  }
 
  public ThreadGroup(String name) {
    this(Thread.currentThread().getThreadGroup(), name);
  }
 
  public ThreadGroup(ThreadGroup parent, String name) {
    this(checkParentAccess(parent), parent, name);
  }
 
  // 线程组对外提供了两个构造函数来进行初始化参数设置
  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); // 把当前线程组添加到父线程组
    // 由以上构造函数可得出几乎每个线程组都存在着父线程组 
  }
 
  // 给线程组设置优先级即:给线程组当中的每个线程设置优先级
  public final void setMaxPriority(int pri) {
    int ngroupsSnapshot;
    ThreadGroup[] groupsSnapshot; // 线程组状态的快照
    synchronized (this) { 
    // object的对象锁,其它线程对该object对象所有同步代码部分的访问都被暂时阻塞,不影响非同步方法的访问
      checkAccess();
      if(pri < Thread.MIN_PRIORITY || pri > Thread.MAX_PRIORITY) {
        return;
      }
      maxPriority=(parent!= null)?Math.min(pri,parent.maxPriority):pri;
      ngroupsSnapshot = ngroups;
      if(groups != null) {
        groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot); // 浅拷贝处理
      }else{
        groupsSnapshot = null;
      }
    }
    for (int i = 0 ; i < ngroupsSnapshot ; i++) {
       groupsSnapshot[i].setMaxPriority(pri);
    }
    // 这里采用递归调用设置线程组中每个线程的优先级
  }
 
  public final void checkAccess() {
    SecurityManager security = System.getSecurityManager();
    if (security != null) {
      security.checkAccess(this);
    }
  }
 
// 返回线程组及其子线程组中活动线程数,返回的只是估计值,因为在这个方法遍历内部数据结构时,线程的数量可能会动态变化,并且可能会受到某些系统线程的影响。此方法主要用于调试和监视目的。
  public int activeCount() {
    int result;
    // Snapshot sub-group data so we don't hold this lock
    // while our children are computing.
    int ngroupsSnapshot;
    ThreadGroup[] groupsSnapshot;
    synchronized (this) {
      if (destroyed) {
        return 0;
      }
      result = nthreads;
      ngroupsSnapshot = ngroups;
      if(groups != null) {
        groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
      }else{
        groupsSnapshot = null;
      }
    }
    for (int i = 0 ; i < ngroupsSnapshot ; i++) {
      result += groupsSnapshot[i].activeCount();
    }
    return result;
  }
 
  // 用来中断线程组中的所有线程,类似setMaxPriority的实现
  public final void interrupt() {
    int ngroupsSnapshot;
    ThreadGroup[] groupsSnapshot;
    synchronized (this) {
      checkAccess();
      for(int i = 0 ; i < nthreads ; i++) {
         threads[i].interrupt();
      }
      ngroupsSnapshot = ngroups;
      if(groups != null) {
        groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
        // Arrays.copyOf可看下它的底层实现,很有用且到处用到
      }else{
        groupsSnapshot = null;
      }
    }
    for(int i = 0 ; i < ngroupsSnapshot ; i++){
      groupsSnapshot[i].interrupt();
    }
  }
 
  // 除了当前线程,剩下的全部干掉,只存在当前线程在线程组则直接返回true
  @SuppressWarnings("deprecation")
  private boolean stopOrSuspend(boolean suspend) {
    boolean suicide = false;
    Thread us = Thread.currentThread();
    int ngroupsSnapshot;
    ThreadGroup[] groupsSnapshot = null;
    synchronized (this) {
      checkAccess();
      for(int i = 0 ; i < nthreads ; i++) {
        if(threads[i]==us)
          suicide = true;
        else if(suspend)
          threads[i].suspend();
        else
          threads[i].stop();
      }
      ngroupsSnapshot = ngroups;
      if(groups != null) {
        groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
      }
    }
    for(int i = 0 ; i < ngroupsSnapshot ; i++)
      suicide = groupsSnapshot[i].stopOrSuspend(suspend) || suicide;
    return suicide;
  }
 
// 在Thread销毁的时候会销毁所属线程组信息,即调用Thread的exit()方法时会调用线程组的threadTerminated()方法,threadTerminated会调用当前方法
  public final void destroy() {
    int ngroupsSnapshot;
    ThreadGroup[] groupsSnapshot;
    synchronized (this) {
      checkAccess();
      if(destroyed || (nthreads > 0)) {
         throw new IllegalThreadStateException();
      }
      ngroupsSnapshot = ngroups;
      if(groups != null) {
        groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
      }else{
        groupsSnapshot = null;
      }
      if (parent != null) { // 系统创建的线程组不包含以下信息 
        destroyed = true;
        ngroups = 0;
        groups = null;
        nthreads = 0;
        threads = null;
      }
    }
    for(int i = 0 ; i < ngroupsSnapshot ; i += 1) {
      groupsSnapshot[i].destroy();
    }
    if(parent != null) {
      parent.remove(this); // 从父线程组中移除当前线程组
    }
  }
 
  // 仅供构造函数使用,注意默认的构造线程组是:4
  private final void add(ThreadGroup g){
    synchronized (this) {
      if(destroyed){
        throw new IllegalThreadStateException();
      }
      if(groups == null) {
        groups = new ThreadGroup[4];
      }else if(ngroups == groups.length) {
        // 不相等的情形,remove()执行完毕但是groups[ngroups]=null,GC未执行?
        groups = Arrays.copyOf(groups, ngroups * 2);
      }
      groups[ngroups] = g;
      // This is done last so it doesn't matter in case the thread is killed
      ngroups++;
    }
  }
 
  // 从线程组中删除指定的线程组
  private void remove(ThreadGroup g) {
    synchronized (this) {
      if(destroyed) {
        return;
      }
      // 循环遍历,存在再进行处理 
      for(int i = 0 ; i < ngroups ; i++) {
        if(groups[i] == g) {
          ngroups -= 1;
          System.arraycopy(groups, i + 1, groups, i, ngroups - i);
          // Zap dangling reference to the dead group so that the GC will collect it.
          groups[ngroups] = null;
          break;
        }
      }
      if(nthreads == 0) {
        notifyAll(); 唤醒synchronized(this)?
      }
      if(daemon && (nthreads == 0)&&(nUnstartedThreads == 0) && (ngroups == 0)){
        destroy(); // 不理解为什么得是daemon? 
      }
    }
  }
 
  // 在new Thread()时会被调动,增加未启动线程的数量
  void addUnstarted() {
    synchronized(this) {
      if(destroyed) {
        throw new IllegalThreadStateException();
      }
      nUnstartedThreads++;
    }
  }
 
  // new Thread().start()时会调用此方法,类似add(ThreadGroup g)的实现
  void add(Thread t) {
    synchronized (this){
      if(destroyed){
        throw new IllegalThreadStateException();
      }
      if(threads == null){
        threads = new Thread[4];
      }else if(nthreads == threads.length) {
        threads = Arrays.copyOf(threads, nthreads * 2);
      }
      threads[nthreads] = t;
      // This is done last so it doesn't matter in case the thread is killed
      nthreads++;
      // 此时就算CPU没有执行,也会被阻止被销毁,未启动数量减1
      nUnstartedThreads--;
    }
  }
 
  // start失败的原因,重复调用start()方法?
  void threadStartFailed(Thread t) {
    synchronized(this) {
      remove(t);
      nUnstartedThreads++;
    }
  }
 
  // 在Thread的exit()方法中被调用
  void threadTerminated(Thread t){
    synchronized (this){
      remove(t);
      if(nthreads == 0){
        notifyAll();
      }
      if(daemon && (nthreads == 0)&&(nUnstartedThreads == 0) && (ngroups == 0)){
        destroy();
      }
    }
  }
 
  // 此处类似remove(ThreadGroup g)的实现
  private void remove(Thread t) {
    synchronized (this) {
      if(destroyed){
        return;
      }
      for(int i = 0 ; i < nthreads ; i++){
        if(threads[i] == t){
          System.arraycopy(threads, i + 1, threads, i, --nthreads - i);
          // Zap dangling reference to the dead thread so that the GC will collect it.
          threads[nthreads] = null;
          break;
        }
      }
    }
  }
 
  // 未指定Thread.UncaughtExceptionHandler且线程在线程组中被stop时会被JVM调用
  * 遵循以下规则:
  * <li>If this thread group has a parent thread group, the
  *     <code>uncaughtException</code> method of that parent is called
  *     with the same two arguments.
  * <li>Otherwise, this method checks to see if there is a
  *     {@linkplain Thread#getDefaultUncaughtExceptionHandler default
  *     uncaught exception handler} installed, and if so, its
  *     <code>uncaughtException</code> method is called with the same
  *     two arguments.
  * <li>Otherwise, this method determines if the <code>Throwable</code>
  *     argument is an instance of {@link ThreadDeath}. If so, nothing
  *     special is done. Otherwise, a message containing the
  *     thread's name, as returned from the thread's {@link
  *     Thread#getName getName} method, and a stack backtrace,
  *     using the <code>Throwable</code>'s {@link
  *     Throwable#printStackTrace printStackTrace} method, is
  *     printed to the {@linkplain System#err standard error stream}.
  * 此方法可以被线程组的子类重写以提供不同的实现 //
  public void uncaughtException(Thread t, Throwable e) {
    if(parent != null) {
      parent.uncaughtException(t, e);
    }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);
      }
    }
  }
 
  // Used by VM to control lowmem implicit suspension.
  @Deprecated
  public boolean allowThreadSuspension(boolean b) {
    this.vmAllowSuspension = b;
    if(!b){
      VM.unsuspendSomeThreads();
    }
    return true;
  }

  public String toString() {
    return getClass().getName()+"[name="+getName()+",maxpri="+maxPriority+"]";
  }
}
 
Note:ThreadGroup中的实现方法比较简单,大部分情况下对线程组的操作会转化为对线程组中的线程的操作【循环递归实现】。虽然ThreadGroup中的实现方法比较简单,但是也存在值得注意的地方,例如锁定当前类对象,需要进行权限校验,会创建快照并且在快照中进行处理,使用Arrays.copyOf()对快照拷贝赋值,递归操作线程组等。在实际运用中ThreadGroup很少被提及,如果需要更好的理解ThreadGroup,需要结合Thread和ThreadDeath源码共同理解。
ThreadGroup中也存在不少废弃的不建议使用的方法,例如:allowThreadSuspension,resume,suspend和stop。