美文网首页
线程Thread中的ThreadGroup

线程Thread中的ThreadGroup

作者: 陈萍儿Candy | 来源:发表于2020-10-28 14:25 被阅读0次

一,ThreadGroup线程组的基本介绍
1.线程组ThreadGroup
为线程服务,用户通过使用线程组的概念批量管理线程,如批量停止或挂起等。 如何做到批量管理线程?????
2.线程和线程组的关系
每个线程创建时,都会纳入线程组的树形结构
3.线程组的树形结构
我们在管理一组对象时往往只是使用数组列表,树形结构的引入解决什么问题,给我们带来什么便利


image.png

4.线程组树形结构
树形结构如上图,一个线程或线程组创建时,必须要获知它的父线程组,一个线程必须要属于某一个线程组。
二,树形结构的代码实现
1.跟节点的唯一性
在ThreadGroup类中,systemThreadGroup确保它的唯一性,使用静态变量,确保全局只有一个对象

 /* the runtime uses these directly; do not rename */
    static final ThreadGroup systemThreadGroup = new ThreadGroup();

2.添加线程节点Thread
需要先计算出它的父线程组,然后把它加入父线程组。每个父线程组维护一个数组Threads[],来保存它的子线程。
计算父线程组有两种方式:
a。指定父线程组
创建线程时指定ThreadGroup

public Thread(ThreadGroup group, Runnable target) {
    init(group, target, "Thread-" + nextThreadNum(), 0);
}

b。或者使用缺省父线程组 parent.getThreadGroup()
构造方法只传入一个Thread

public Thread(Runnable target) {
    init(null, target, "Thread-" + nextThreadNum(), 0);
}

private void init(ThreadGroup g, Runnable target, String name, long stackSize) {
    Thread parent = currentThread();
    if (g == null) {
        g = parent.getThreadGroup();
    }
    //新线程继承父线程组的优先级
    this.target = target;
    this.priority = parent.getPriority();
    this.daemon = parent.isDaemon();
     ...
}

线程节点的增加,ThreadGroup.java中

3.ThreadGroup 中add(Thread t)方法:

Thread threads[];
void add(Thread t) {
    synchronized (this) {
        if (destroyed) {
            throw new IllegalThreadStateException();
        }
        if (threads == null) {
//   里面有一个线程数组   数组的扩容和arraylist类似. 自动扩展
            threads = new Thread[4];
        } else if (nthreads == threads.length) {
            threads = Arrays.copyOf(threads, nthreads * 2);
        }
//.  添加节点到threads[]
        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--;
    }
}

threads[]数组实现了自动扩展,因为它无法确定子线程节点有多少。
threads[]的初始长度是4,如果满了,就以2倍速度扩展,8,16,…

4.添加线程组节点ThreadGroup
需要计算其父线程组节点,然后父线程组纳入此节点。每个父线程组通过维护groups[],来保存它的子线程组节点。
ThreadGroup中的add(ThreadGroup g)

ThreadGroup groups[];

private final void add(ThreadGroup g){

    //实现groups数组的自动扩展
    if (groups == null) {
        groups = new ThreadGroup[4];
    } else if (ngroups == groups.length) {
        groups = Arrays.copyOf(groups, ngroups * 2);
    }
    
    //添加节点到groups[]
    groups[ngroups] = g;
}

5.移除子线程节点或子线程组节点

子线程节点和子线程组节点的移除操作一致,不同的是操作的列表不同,子线程节点操作的是threads[],而子线程组节点操作的是groups[]。这里只以子线程节点为例。ThreadGroup中的remove(Thread t)

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;
                }
            }
        }
    }

首先要先理解System.arraycopy函数的基本用法

public static native void arraycopy(Object src,  int  srcPos,
                                        Object dest, int destPos,
                                        int length);

其中,src表示源数组,srcPos表示源数组要复制的起始位置,desc表示目标数组,length表示要复制的长度。
具体可以参考以下博客:
System.arraycopy()方法详解
可以看到,arraycopy是一种浅复制,但此处却利用它实现了数组的删除。举个例子,已知thread[]有A,B,C,D子线程节点,现在要删除B节点。
如以下图所示:

image.png
巧妙地通过sytem.arraycopy,自身列表对自身列表的复制操作,实现删除。很简洁。
6.集合操作时的递归遍历
可以说,树形结构为集合操作提供很简洁的形式,就是支持递归遍历。举个例子,ThreadGroup中
public final void interrupt() {
        int ngroupsSnapshot;
        ThreadGroup[] groupsSnapshot;
        synchronized (this) {
            checkAccess();
            //thread遍历
            for (int i = 0 ; i < nthreads ; i++) {
                threads[i].interrupt();
            }
            ngroupsSnapshot = ngroups;
            if (groups != null) {
                groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
            } else {
                groupsSnapshot = null;
            }
        }
        //threadGroup递归遍历
        for (int i = 0 ; i < ngroupsSnapshot ; i++) {
            groupsSnapshot[i].interrupt();
        }
    }

第一部分,是对thread子节点直接使用for循环进行遍历。
第二部分,对threadGroup子节点调用本函数,递归遍历。
总结:
threadGroup通过把各个thread组织成树形结构,新的thread创建时会默认继承父线程组的优先级,对于批量处理thread有更加细致的操作选择,满足用户更多的批量处理需求。

相关文章

网友评论

      本文标题:线程Thread中的ThreadGroup

      本文链接:https://www.haomeiwen.com/subject/vknumktx.html