章
目
录
本文重点介绍Java多线程:线程管理之线程组相关知识。Java线程组是一种用于管理线程的机制,类似于在计算机中使用文件夹管理文件,也可以使用线程组来管理线程,在线程组中定义一组相似(相关)的线程。也可以在线程组中定义子线程组。
什么是线程组?
线程组是一个用于组织和管理线程的对象。它可以包含多个线程,将它们组织成一个单元,从而更容易进行管理和控制。线程组有助于将相关线程分组,便于监视和协调它们的行为。
ThreadGroup类的构造函数
Java线程组由java.lang.ThreadGroup
类实现。
ThreadGroup类有2个构造函数,其中一个允许你指定线程组的名称和父线程组。
编号 | 构造函数 | 描述 |
---|---|---|
1 | ThreadGroup(String name) |
创建具有给定名称的线程组。 |
2 | ThreadGroup(ThreadGroup parent, String name) |
创建具有给定父组和名称的线程组。 |
如何创建线程组?
要创建线程组,你可以使用ThreadGroup类的构造函数。
代码示例:
ThreadGroup parentGroup = new ThreadGroup("ParentGroup"); // 创建一个名为ParentGroup的线程组
ThreadGroup childGroup = new ThreadGroup(parentGroup, "ChildGroup"); // 创建一个名为ChildGroup的子线程组
在上面的示例中,我们首先创建了一个名为ParentGroup
的线程组,然后在该组内创建了一个名为ChildGroup
的子线程组。线程组可以形成层级结构,其中子线程组可以包含在父线程组内。
线程组ThreadGroup类的方法
编号 | 方法 | 描述 |
---|---|---|
1 | void checkAccess() | 此方法确定当前运行的线程是否具有修改线程组的权限。 |
2 | int activeCount() | 此方法返回线程组及其子组中活动线程数的估计值。 |
3 | int activeGroupCount() | 此方法返回线程组及其子组中活动组数量的估计值。 |
4 | void destroy() | 此方法会销毁线程组及其所有子组。 |
5 | int enumerate(Thread[] list) | 此方法将线程组及其子组中的每个活动线程复制到指定的数组中。 |
6 | int getMaxPriority() | 此方法返回线程组的最大优先级。 |
7 | String getName() | 此方法返回线程组的名称。 |
8 | ThreadGroup getParent() | 此方法返回线程组的父级。 |
9 | void interrupt() | 此方法中断线程组中的所有线程。 |
10 | boolean isDaemon() | 此方法测试线程组是否为守护程序线程组。 |
11 | void setDaemon(boolean daemon) | 此方法更改线程组的守护程序状态。 |
12 | boolean isDestroyed() | 此方法测试此线程组是否已被销毁。 |
13 | void list() | 此方法将有关线程组的信息打印到标准输出。 |
14 | boolean parentOf(ThreadGroup g) | 此方法测试线程组是线程组参数还是其祖先线程组之一。 |
15 | void suspend() | 此方法用于挂起线程组中的所有线程。 |
16 | void resume() | 此方法用于恢复使用suspend() 方法挂起的线程组中的所有线程。 |
17 | void setMaxPriority(int pri) | 此方法设置组的最大优先级。 |
18 | void stop() | 此方法用于停止线程组中的所有线程。 |
19 | String toString() | 此方法返回线程组的字符串表示形式。 |
获取线程所在线程组
JVM在创建main线程时会为它指定一个线程组,因此每个Java线程都有一个线程组与之关联,可以调用线程的getThreadGroup()方法返回该线程的线程组。
另外,说明下,Thread类有几个构造方法,其中一个允许在创建线程时指定线程组,如果在创建线程时没有指定线程组,则该线程就属于父线程所在的线程组。
public class Test01 {
public static void main(String[] args) {
//返回当前main线程的线程组
ThreadGroup mainGroup = Thread.currentThread().getThreadGroup();
// System.out.println(mainGroup);
//定义线程组,如果没有指定它的父线程组,那么它就是当前这个线程组的子线程组
ThreadGroup group1 = new ThreadGroup("group1");
// System.out.println(group1);
// System.out.println(group1.getParent());
//也可以指定父线程组
ThreadGroup group2 = new ThreadGroup(mainGroup, "group2");
// System.out.println(group2.getParent());
//创建线程时指定所属线程组
Runnable r = new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread());
}
};
//创建线程时,如果没有指定线程组,默认归属到父线程的线程组中
//我们在main线程中创建了t线程,所以t线程是main线程的子线程
//如果t线程没有指定线程组,那么它的线程组就是默认为main线程的线程组
Thread t = new Thread(r);
System.out.println(t);
//创建线程时,可以指定线程所属的线程组
Thread t2 = new Thread(group1, r, "t2");
Thread t3 = new Thread(group2, r, "t3");
System.out.println(t3);
}
}
复制线程组中的线程及其子线程、获取活动线程数
代码示例:
public class Test03 {
public static void main(String[] args) {
ThreadGroup mainGroup = Thread.currentThread().getThreadGroup();
Runnable r = new Runnable() {
@Override
public void run() {
try {
TimeUnit.SECONDS.sleep(1000);
} catch (InterruptedException e){
e.printStackTrace();
}
}
};
Thread m1 = new Thread(mainGroup, r);
Thread m2 = new Thread(mainGroup, r);
ThreadGroup group1 = new ThreadGroup("group1");
Thread g1 = new Thread(group1, r);
Thread g2 = new Thread(group1, r);
m1.start();
m2.start();
g1.start();
g2.start();
ThreadGroup group2 = new ThreadGroup(group1, "group2");
Thread[] list = new Thread[mainGroup.activeCount()];
ThreadGroup[] groupList = new ThreadGroup[mainGroup.activeGroupCount()];
mainGroup.enumerate(list, false);
mainGroup.enumerate(groupList, false);
System.out.println("开始打印");
System.out.println(list.length);
System.out.println(groupList.length);
for(Thread thread : list) {
System.out.println(thread);
}
for(ThreadGroup group : groupList) {
System.out.println(group);
}
}
}
线程组的批量中断
线程组的interrupt()方法可以给线程组中的所有线程添加中断标志。
public class Test04 {
public static void main(String[] args) throws InterruptedException {
Runnable r = new Runnable() {
@Override
public void run() {
while(!Thread.interrupted()) {
System.out.println(Thread.currentThread().getName() + "is running");
}
System.out.println(Thread.currentThread().getName() + "is interrupted");
}
};
ThreadGroup mainGroup = Thread.currentThread().getThreadGroup();
Thread t1 = new Thread(mainGroup, r);
Thread t2 = new Thread(mainGroup, r);
ThreadGroup group1 = new ThreadGroup(mainGroup, "g1");
Thread t3 = new Thread(group1, r);
Thread t4 = new Thread(group1, r);
t1.start();
t2.start();
t3.start();
t4.start();
TimeUnit.SECONDS.sleep(1);
mainGroup.interrupt();
}
}
设置守护线程组
守护线程是为其他线程服务的,当JVM中只有守护线程时,守护线程会被销毁,JVM退出。
线程组的setDaemon(true)方法可以把线程组设置为守护线程组,当守护线程组中没有活动线程时,守护线程组被销毁。
守护线程组的守护属性,与其线程的守护属性无关。
挂起和恢复线程组
你可以使用suspend()
方法来挂起线程组内的所有线程,使用resume()
方法来恢复线程组内的所有线程。这些方法通常用于暂时停止线程组的执行。
suspend()
,resume()
和stop()
方法。线程组的销毁
如果你不再需要线程组,可以使用destroy()
方法销毁它。销毁线程组将导致线程组内的所有线程停止并被移除。
其他的API方法就不再详细说明,具体参照表格自行研究即可!
线程组的注意事项
- 线程组并不是线程安全的,因此在线程组内的线程之间共享数据时需要注意同步。
- 销毁线程组将停止组内的所有线程,请谨慎使用。
- 线程组的嵌套结构应谨慎设计,以免过度复杂化线程管理。
线程组的常见用法
线程组的任务分组
一个常见的用法是将相关任务分组到不同的线程组中。例如,一个应用程序可能有多个不同的任务,如用户界面、后台任务、网络通信等。你可以为每个任务创建一个独立的线程组,以便更好地管理和监视这些任务。
ThreadGroup uiGroup = new ThreadGroup("UIGroup");
ThreadGroup backgroundGroup = new ThreadGroup("BackgroundGroup");
ThreadGroup networkGroup = new ThreadGroup("NetworkGroup");
定时任务
线程组还可以用于执行定时任务。你可以创建
一个定时任务线程组,然后在该组内创建定时任务线程,以执行特定的定时操作。
ThreadGroup timerGroup = new ThreadGroup("TimerGroup");
TimerTask timerTask = new TimerTask(timerGroup);
timerTask.start();
线程池
线程池通常使用线程组来组织线程。线程池会创建一个线程组来包含池内的所有线程,这样就可以轻松地管理和监视线程池的活动。
ExecutorService executor = Executors.newFixedThreadPool(5);
ThreadGroup threadPoolGroup = executor.getThreadGroup();
线程组的主要作用
- 组织:将相似或相关的线程放在同一个组内,便于管理。
- 控制:可以对整个线程组执行操作,如挂起、恢复、中断等。
- 监视:可以获取线程组的状态信息,如活动线程数、线程组名称等。
- 安全性:线程组可以用于设置安全性策略,限制组内线程的权限。
总结
以上就是Java多线程:线程管理之线程组的全部内容。