线程组简介
在 Java 中,ThreadGroup用于表示一个线程组。我们可以使用ThreadGroup来批量控制线程,更方便地管理线程。
ThreadGroup和Thread之间的关系非常简单,就像它们的字面意思一样:每个Thread必然存在于一个ThreadGroup中,一个Thread不能独立于ThreadGroup存在。
执行main()方法的线程名字是main,如果你在执行new Thread()时没有显式指定一个ThreadGroup,那么默认会将父线程(当前正在执行new Thread()的线程)的ThreadGroup设置为子线程的ThreadGroup。
示例代码:
输出:
线程组是父子结构的,一个线程组可以包含其他线程组,也可以有其他子线程组。从结构上看,线程组是一个树形结构,每个线程属于一个线程组,而该线程组又有一个父线程组,依此类推,最终可以追溯到根线程组,即System线程组。
结构如下所示:
图片
- JVM 创建的system线程组是一组用于处理 JVM 系统任务的线程,比如对象销毁、垃圾回收(GC)等。
- system线程组的直接子线程组是main线程组,它至少包含一个执行main方法的main线程。
- main线程组的子线程组是由应用程序创建的线程组。
你可以在main方法中看到 JVM 创建的system线程组和main线程组:
输出:
一个线程可以访问它所属线程组的信息,但不能访问它所属线程组的父线程组或其他线程组的信息。
线程组的结构
首先,我们来看一下ThreadGroup源码中的成员变量。
接下来,我们看一下java.lang.ThreadGroup提供的两个构造函数,我添加了一些注释以便理解。
checkParentAccess()方法用于判断当前运行的线程是否有权限修改线程组。
以下代码演示了这两个构造函数的用法:
输出:
ThreadGroup 包含的方法
ThreadGroup提供了许多有用的方法,下面简要介绍其中一些。
方法 | 描述 |
void checkAccess() | 判断当前运行的线程是否有权限修改线程组。 |
int activeCount() | 返回线程组及其子组中活动线程的估计数量。 |
int activeGroupCount() | 返回线程组及其子组中活动线程组的估计数量。 |
void destroy() | 销毁线程组及其所有子组。 |
int enumerate(Thread[] list) | 将线程组及其子组中的所有活动线程复制到指定的数组中。 |
int getMaxPriority() | 返回线程组的最大优先级。 |
String getName() | 返回线程组的名称。 |
ThreadGroup getParent() | 返回线程组的父线程组。 |
void interrupt() | 中断线程组中的所有线程。 |
boolean isDaemon() | 判断线程组是否是守护线程组。 |
void setDaemon(boolean daemon) | 设置线程组的守护状态。 |
boolean isDestroyed() | 判断线程组是否已被销毁。 |
void list() | 将线程组的信息打印到标准输出。 |
boolean parentOf(ThreadGroup g) | 判断线程组是否是参数线程组或其祖先线程组。 |
void suspend() | 挂起线程组中的所有线程。 |
void resume() | 恢复线程组中所有被挂起的线程。 |
void setMaxPriority(int prt) | 设置线程组的最大优先级。 |
void stop() | 停止线程组中的所有线程。 |
String toString() | 返回线程组的字符串表示。 |
我们选择其中一些方法来演示用法。
输出:
这里有一个有趣的地方:当输出当前线程组中的活动线程数量时,实际上并没有计算状态为NEW和TERMINATED的线程。所以当输出subgroup1.activeCount()时,实际上只有一个活动线程,即t2,因为t1已经结束,而t3还没有启动。
总结
简单来说,线程组是一个树形结构,每个线程组下可以有多个线程或多个线程组。线程组可以用于统一控制线程的优先级、检查线程的权限等。