Java ThreadGroup Java Doc 和源码解读

486 阅读12分钟

基础知识

正文

ThreadGroup是Thread.UncaughtExceptionHandler的一个实现类,一个线程组代表一组线程。而且,一个线程组还可能包含其他的线程组。这些线程组组成了一棵树,除了最初的线程组。一个线程可以访问他自己的线程组信息,但是不能去方法它父线程组或其他线程组的信息。

构造器

public ThreadGroup(String name)

构造一个新的线程组。这个新线程组的父亲就是当前线程的线程组。

Parameters:
name - 线程组名称
Throws:
SecurityException - checkAccess方法可能会抛出异常

public ThreadGroup(ThreadGroup parent,String name)

使用指定的父线程组对象,创建新的线程组,并指定名称。

Parameters:
parent - 父线程组 name - 新线程组的名称
Throws:
NullPointerException - if the thread group argument is null.
SecurityException - if the current thread cannot create a thread in the specified thread group.

方法

public final String getName()

返回线程组名。

public final ThreadGroup getParent()

返回父线程组。只有最顶级的线程组的父线程组是null。
Throws:
SecurityException - if the current thread cannot modify this thread group.

public final int getMaxPriority()

返回这个线程组的最大优先级。这个线程组中的线程优先级不能超过这个值。

public final boolean isDaemon()

检测这个线程组是不是一个守护线程组。当组内的守护线程已停止,守护线程组会自动销毁。
Returns 如果这个线程组是一个守护线程组就返回true。

public boolean isDestroyed()

检查这个线程组是否已经销毁。
Returns:
如果已经销毁就返回true

public final void setDaemon(boolean daemon)

修改守护线程标志。
Parameters:
daemon - true:标记这个线程组是守护线程组; false:就是个普通的线程组。

public final void setMaxPriority(int pri)

设置线程组的最大优先级。线程组中的线程如果有更大的优先级,也不会起作用,主要取决于线程组的最大优先级。 参数必须在[Thread.MIN_PRIORITY,Thread.MAX_PRIORITY]这个范围内,否则也不会起作用。这个方法会递归的调用,设置当前线程组和它的子组的优先级。实际是否起作用,取决于pri参数和当前线程组的父线程组的优先级的大小,取两者之间小的那个值。
Parameters:
pri - 新的线程优先级

public final boolean parentOf(ThreadGroup g)

检查这个线程组是否是参数线程组的祖先。

public final void checkAccess()

检查当前线程是否有权限修改这个线程组。

public int activeCount()

返回当前线程组和线程子组的活跃线程数(估算值)。这个方法主要用于调试和监控。

public int enumerate(Thread[] list)

拷贝当前线程组和线程子组的所有活跃线程到参数数组中,并返回线程数。调用这个方法与调用enumerate(list, true)是等价的。
Parameters:
list - 用于存放线程的数组 Returns:
线程数

public int enumerate(Thread[] list,boolean recurse)

拷贝当前线程组和线程子组的所有活跃线程到参数数组中,并返回线程数。如果recurese=true,这个方法会递归的枚举所有线程子组,把它们的活跃线程也算进结果中。如果数组长度太小,那么多余的线程会被忽略。 这个方法最好仅用于debug或者监控场景。

Parameters:
list - 线程数组,用于存放所有活跃线程的引用
recurse - true:递归地枚举所有线程子组的情况
Returns: 线程数量

public int activeGroupCount()

返回活跃线程组和它的子组,这是一个预估的值。递归地迭代这个线程组的所有线程子组。

public int enumerate(ThreadGroup[] list)

将活跃的线程组拷贝至list数组,和enumerate(list, true)是等价的,具体看上面

public int enumerate(ThreadGroup[] list,boolean recurse)

一个意思

public final void interrupt()

打断这个线程组的所有线程。这个方法会对这个线程组中的所有线程和所有线程子组的线程调用interrupt方法。

public final void destroy()

销毁这个线程组和所有线程子组。这个线程组必须为空,也就是说组内的所有线程都已经stop了。
Throws:
IllegalThreadStateException - 如果线程组不为空,或者线程组已经被销毁了

public void list()

打印这个线程组的信息到标准输出。这个方法只用于debug模式。

public void uncaughtException(Thread t,Throwable e)

这个方法就不多说,ThreadGroup是Thread.UncaughtExceptionHandler接口的实现类,所以这个方法其实是ThreadGroup的一个核心方法。具体请看Thread.UncaughtExceptionHandler的帖子。

public String toString()

不多说了,就是打印一下信息。

源码解读

package java.lang;

import java.io.PrintStream;
import java.util.Arrays;
import sun.misc.VM;

/**
 * 
 * ThreadGroup 实现了 Thread.UncaughtExceptionHandler
 */
public class ThreadGroup implements Thread.UncaughtExceptionHandler {
    //父线程组的引用,一般就是当前线程的线程组
    private final ThreadGroup parent;
    //线程组名称
    String name;
    //最大优先级
    int maxPriority;
    //销毁标记
    boolean destroyed;
    //守护线程组标记
    boolean daemon;
    //没什么用
    boolean vmAllowSuspension;
    //未start的线程数
    int nUnstartedThreads = 0;
    int nthreads;
    //组内线程数组
    Thread threads[];
    
    int ngroups;
    //线程子组
    ThreadGroup groups[];

    /**
     * 创建一个空线程组,这个方法是private的,一般人无法调用,这个方法是JVM创建系统线程组时调用的
     */
    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;
        //父线程组将这个线程组,add到父线程组的线程子组数组中
        parent.add(this);
    }

    /*
     * 校验是否有权限
     */
    private static Void checkParentAccess(ThreadGroup parent) {
        parent.checkAccess();
        return null;
    }

    /**
     * 返回这个线程组的名称
     */
    public final String getName() {
        return name;
    }

    /**
     * 返回这个线程组的父线程组
     */
    public final ThreadGroup getParent() {
        if (parent != null)
            parent.checkAccess();
        return parent;
    }

    /**
     * 返回最大优先级
     */
    public final int getMaxPriority() {
        return maxPriority;
    }

    /**
     * 返回这个线程组的守护线程标志
     */
    public final boolean isDaemon() {
        return daemon;
    }

    /**
     * 判断这个线程组是否已经被销毁
     */
    public synchronized boolean isDestroyed() {
        return destroyed;
    }

    /**
     * 设置线程组的守护线程标志
     */
    public final void setDaemon(boolean daemon) {
        checkAccess();
        this.daemon = daemon;
    }

    /**
     * 设置线程组的最大优先级
     */
    public final void setMaxPriority(int pri) {
        int ngroupsSnapshot;
        ThreadGroup[] groupsSnapshot;
        synchronized (this) {
            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 boolean parentOf(ThreadGroup g) {
        for (; g != null ; g = g.parent) {
            if (g == this) {
                return true;
            }
        }
        return false;
    }

    /**
     * 判断有没有权限
     */
    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;
    }

    /**
     * 拷贝活跃线程,一般用于监控,递归的拷贝子线程组
     */
    public int enumerate(Thread list[]) {
        checkAccess();
        return enumerate(list, 0, true);
    }

    /**
     * 拷贝活跃线程,一般用于监控,recurse=true就递归的拷贝子线程组
     */
    public int enumerate(Thread list[], boolean recurse) {
        checkAccess();
        return enumerate(list, 0, recurse);
    }
    /**
     * 拷贝活跃线程,一般用于监控,recurse=true就递归的拷贝子线程组
     */
    private int enumerate(Thread list[], int n, boolean recurse) {
        int ngroupsSnapshot = 0;
        ThreadGroup[] groupsSnapshot = null;
        synchronized (this) {
            if (destroyed) {
                return 0;
            }
            int nt = nthreads;
            if (nt > list.length - n) {
                nt = list.length - n;
            }
            for (int i = 0; i < nt; i++) {
                if (threads[i].isAlive()) {
                    list[n++] = threads[i];
                }
            }
            if (recurse) {
                ngroupsSnapshot = ngroups;
                if (groups != null) {
                    groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
                } else {
                    groupsSnapshot = null;
                }
            }
        }
        if (recurse) {
            for (int i = 0 ; i < ngroupsSnapshot ; i++) {
                n = groupsSnapshot[i].enumerate(list, n, true);
            }
        }
        return n;
    }

    /**
     * 返回活跃线程组数量,只要线程组没有被销毁,就算作一个活跃线程组
     * 递归的计算所有子线程组
     */
    public int activeGroupCount() {
        int ngroupsSnapshot;
        ThreadGroup[] groupsSnapshot;
        synchronized (this) {
            if (destroyed) {
                return 0;
            }
            ngroupsSnapshot = ngroups;
            if (groups != null) {
                groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
            } else {
                groupsSnapshot = null;
            }
        }
        int n = ngroupsSnapshot;
        for (int i = 0 ; i < ngroupsSnapshot ; i++) {
            n += groupsSnapshot[i].activeGroupCount();
        }
        return n;
    }

    /**
     * 拷贝当前线程组的所有线程子组和他们的后代线程组到参数数组中
     */
    public int enumerate(ThreadGroup list[]) {
        checkAccess();
        return enumerate(list, 0, true);
    }

    /**
     * 拷贝当前线程组的所有线程子组到参数数组中,recurse=true就把他们的
     * 后代也拷贝
     */
    public int enumerate(ThreadGroup list[], boolean recurse) {
        checkAccess();
        return enumerate(list, 0, recurse);
    }

    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) {
                ng = list.length - n;
            }
            if (ng > 0) {
                System.arraycopy(groups, 0, list, n, ng);
                n += ng;
            }
            if (recurse) {
                ngroupsSnapshot = ngroups;
                if (groups != null) {
                    groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
                } else {
                    groupsSnapshot = null;
                }
            }
        }
        if (recurse) {
            for (int i = 0 ; i < ngroupsSnapshot ; i++) {
                n = groupsSnapshot[i].enumerate(list, n, true);
            }
        }
        return n;
    }

    /**
     * 过时了,别用,因为他调用了Thread的stop(也过时了)
     */
    @Deprecated
    public final void stop() {
        if (stopOrSuspend(false))
            Thread.currentThread().stop();
    }

    /**
     * 打断当前线程组中的所有线程,也会打点子线程组的所有线程
     */
    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);
            } else {
                groupsSnapshot = null;
            }
        }
        for (int i = 0 ; i < ngroupsSnapshot ; i++) {
            groupsSnapshot[i].interrupt();
        }
    }

    /**
     * 挂起线程,别用,也过时了
     */
    @Deprecated
    @SuppressWarnings("deprecation")
    public final void suspend() {
        if (stopOrSuspend(true))
            Thread.currentThread().suspend();
    }

    /**
     * 别用,不过是private,也没法用
     */
    @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;
    }

    /**
     * 过时了
     */
    @Deprecated
    @SuppressWarnings("deprecation")
    public final void resume() {
        int ngroupsSnapshot;
        ThreadGroup[] groupsSnapshot;
        synchronized (this) {
            checkAccess();
            for (int i = 0 ; i < nthreads ; i++) {
                threads[i].resume();
            }
            ngroupsSnapshot = ngroups;
            if (groups != null) {
                groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
            } else {s
                groupsSnapshot = null;
            }
        }
        for (int i = 0 ; i < ngroupsSnapshot ; i++) {
            groupsSnapshot[i].resume();
        }
    }

    /**
     * 销毁线程组和所有线程子组,这个组里的线程必须都不活跃才可以
     */
    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);
        }
    }

    /**
     * 把参数线程组添加到当前线程组
     */
    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) {
                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 garbage collector will collect it.
                    groups[ngroups] = null;
                    break;
                }
            }
            if (nthreads == 0) {
                notifyAll();
            }
            if (daemon && (nthreads == 0) &&
                (nUnstartedThreads == 0) && (ngroups == 0))
            {
                destroy();
            }
        }
    }


    /**
     * 未启动线程数+1,用于记录那些未启动的线程数。
     */
    void addUnstarted() {
        synchronized(this) {
            if (destroyed) {
                throw new IllegalThreadStateException();
            }
            nUnstartedThreads++;
        }
    }

    /**
     * 添加线程到这个线程组
     */
    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++;

            // The thread is now a fully fledged member of the group, even
            // though it may, or may not, have been started yet. It will prevent
            // the group from being destroyed so the unstarted Threads count is
            // decremented.
            nUnstartedThreads--;
        }
    }

    /**
     * 这个方法是Thread调用的,当Thread.start方法执行失败时会调用此方法
     * 他也会调用remove方法,remove会导致线程组的线程数组出现移动
     */
    void threadStartFailed(Thread t) {
        synchronized(this) {
            remove(t);
            nUnstartedThreads++;
        }
    }

    /**
     * 这个方法其实主要是Thread调用的,当Thread结束执行退出时,会调用线程组的
     * 这个方法,这样会导致线程组的线程数组出现移动,这其实是一个优化点
     */
    void threadTerminated(Thread t) {
        synchronized (this) {
            remove(t);

            if (nthreads == 0) {
                notifyAll();
            }
            if (daemon && (nthreads == 0) &&
                (nUnstartedThreads == 0) && (ngroups == 0))
            {
                destroy();
            }
        }
    }

    /**
     * 将线程从这个组内删除
     */
    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 garbage collector will collect it.
                    threads[nthreads] = null;
                    break;
                }
            }
        }
    }

    /**
     * 打印线程组到标准输出,主要用于debug
     */
    public void list() {
        list(System.out, 0);
    }
    void list(PrintStream out, int indent) {
        int ngroupsSnapshot;
        ThreadGroup[] groupsSnapshot;
        synchronized (this) {
            for (int j = 0 ; j < indent ; j++) {
                out.print(" ");
            }
            out.println(this);
            indent += 4;
            for (int i = 0 ; i < nthreads ; i++) {
                for (int j = 0 ; j < indent ; j++) {
                    out.print(" ");
                }
                out.println(threads[i]);
            }
            ngroupsSnapshot = ngroups;
            if (groups != null) {
                groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
            } else {
                groupsSnapshot = null;
            }
        }
        for (int i = 0 ; i < ngroupsSnapshot ; i++) {
            groupsSnapshot[i].list(out, indent);
        }
    }

    /**
     * 不多说了,去看Thread.UncaughtException
     */
    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);
            }
        }
    }

    /**
     * 过时了,不多说
     */
    @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 + "]";
    }
}

总结

ok,源码看完发现其实也不是很难理解,但是你可能会和我一样有很多疑问,例如: Tomcat作为一个Web容器,它在线程组这部分一定也有设计,那么是如何设计的呢?因为你看ThreadGroup的源码,你一定会发现这里面其实有个地方很耗费资源,那就是ThreadGroup的add和remove方法会对线程数组进行移位和拷贝,这样就很耗费资源。像Tomcat这种处理Http请求的场景,线程不断地创建和死亡,每次创建线程和线程销毁都要去对数组进行拷贝、移位,势必会对性能造成影响,如果使用链表可能会更好一些。而ThreadGroup这个类并没有给我们选择的余地,不知道阿里这种大厂会不会基于这个点去优化。后面我会去找下Tomcat的源码,单开一篇帖子去验证一下Tomcat的线程组是如何设计的。

在一般的生产环境中,Tomcat的线程数在200左右时,一台2C4G配置的服务器CPU压力基本就已经拉满了,不知道这个线程组如果优化一下能有多少提升,可以想象一下,系统压力足够高时,线程数维持在200,请求响应速度极快,ThreadGroup不停的add和remove,这个性能损耗还是挺高的。优化的办法无非就是两个:1.重新编译JDK;2.使用ClassLoader技术动态替换JDK的class。ClassLoader我玩儿的不6,第二种不知道可不可行,但是可以试试,有大神看到也可以讨论下。