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

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节点。
如以下图所示:

巧妙地通过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有更加细致的操作选择,满足用户更多的批量处理需求。
网友评论