线程组
程序员文章站
2022-05-05 16:35:38
...
线程组的核心在于方便批量管理同一类线程,定义线程的共性行为。比如某个线程出现异常,则中断该组中所有线程。
推荐博文 https://www.cnblogs.com/noteless/p/10354721.html#
1. 私有的无参构造方法会构造一个system线程组,也被称之为根线程组。该方法由C代码调用
/**
* Creates an empty Thread group that is not in any Thread group.
* This method is used to create the system Thread group.
*/
private ThreadGroup() { // called from C code
this.name = "system";
this.maxPriority = Thread.MAX_PRIORITY;
this.parent = null;
}
1. 从构造方法上来看,每个线程组(非system)必定有它的父线程组,不指定的话,默认为当前线程所属的线程组 Thread.currentThread().getThreadGroup()
2. 从线程Thread的核心构造方法来看,如果线程在创建时不指定所属线程组,默认为父线程(姑且称之)所属的线程组,但是要注意的是,这里只是指定了父线程组,至于线程组中用来记录并存储组中线程的容器数组 Thread threads[] 并未加入该线程,仅当线程调用start方法并成功启动后,才算真正加入。
联系ThreadGroup中的方法可知,
3. 有关线程组的枚举方法,虽然没用过,这里简单分析一下枚举线程组中的线程,枚举子线程组的方法与其类似,跳过
/**
* 参数list,一个用来装线程对象的数组容器,方法调用者自己传入,通常为一个空容器
* 参数recurse,是否递归取得所有子孙组中的线程对象,默认为true
* 参数n,调用者无法传入,公有的enumerate方法中未设置该参数,默认为0,在递归时被赋值,保证放入的线程对象不超出list长度
*/
private int enumerate(Thread list[], int n, boolean recurse) {
int ngroupsSnapshot = 0;
ThreadGroup[] groupsSnapshot = null;
synchronized (this) {
if (destroyed) {
return 0;
}
// nthreads表示该组中的所有线程数
int nt = nthreads;
// nt值受容器大小影响
if (nt > list.length - n) {
nt = list.length - n;
}
// 这里即将本组中的线程对象放入容器中
for (int i = 0; i < nt; i++) {
// 只保存alive状态的
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);
}
}
// 返回实际放入list中的线程对象数目
return n;
}
另外附上一个自己写的测试demo
package thread;
/**
* @author LiFeng
* @create 2019-11-04 上午 8:45
* @describe
*/
public class TestThreadGroup {
public static void main(String[] args) {
Runnable target = new Runnable() {
@Override
public void run() {
try {
// 这里让线程休眠5s,避免线程执行完退出,保证main先执行完,不然结果可能不符合预期
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
// 不指定父线程组,则默认父线程组为当前线程组,即main线程组
ThreadGroup mytg1 = new ThreadGroup("main-my-tg1");
// 指定 mytg1 为父线程组
ThreadGroup mytg2 = new ThreadGroup(mytg1, "main-my-tg1-tg2");
// 该方法返回当前线程组所有子、孙线程组的总个数,注意,这是一个估计值,因为其内部结构可能会动态改变。该方法主要用于测试与监控
int activeGroupCount = Thread.currentThread().getThreadGroup().activeGroupCount();
// 初始化容器,预期容量同activeGroupCount
ThreadGroup[] tgarr = new ThreadGroup[activeGroupCount];
// 默认递归方式,取得所有子孙线程组
int enumerate = Thread.currentThread().getThreadGroup().enumerate(tgarr);
for (int i = 0; i < enumerate; i++) {
System.out.println(tgarr[i].getName());
}
System.out.println("-------------------------------------");
// 非递归方式
ThreadGroup[] tgarr2 = new ThreadGroup[activeGroupCount];
int enumerate2 = Thread.currentThread().getThreadGroup().enumerate(tgarr2, false);
for (int i = 0; i < enumerate2; i++) {
System.out.println(tgarr2[i].getName());
}
System.out.println("-------------------------------------");
Thread a = new Thread(target, "main-a");
Thread b = new Thread(mytg1, target, "main-mytg1-b");
Thread c = new Thread(mytg2, target, "main-mytg1-mytg2-c");
// 注意,这里必须启动才算真正加入线程组中
a.start();
b.start();
c.start();
// 类似上面的activeGroupCount方法,不介绍了
int activeCount = Thread.currentThread().getThreadGroup().activeCount();
Thread[] tarr = new Thread[activeCount];
int enumerate3 = Thread.currentThread().getThreadGroup().enumerate(tarr);
for (int i = 0; i < enumerate3; i++) {
System.out.println(tarr[i].getName());
}
System.out.println("-------------------------------------");
Thread[] tarr2 = new Thread[activeCount];
int enumerate4 = Thread.currentThread().getThreadGroup().enumerate(tarr2, false);
for (int i = 0; i < enumerate4; i++) {
System.out.println(tarr2[i].getName());
}
System.out.println();
}
}
输出结果如下:
结果是符合预期的,只是多了一些额外的东西~~,这个Monitor Ctrl-Break 线程是跟随main线程一起运行起来的,具体的不了解,不做深究。自行Google。
好了,我暂时真的不想在这个东西上花太多时间,有机会再深入。
上一篇: XDepend 1.0 发布:简化Java代码操作的工具
下一篇: 多线程学习: 线程中断