0%

java多线程系列07ThreadGroup

在java的多线程中有线程组ThreadGroup的概念,ThreadGroup是为了方便线程管理而出现,可以统一设定线程组的一些属性,比如setDaemon,设置未处理异常的处理方法,设置统一的安全策略等等;也可以通过线程组方便的获得线程的一些信息。

每一个ThreadGroup都可以包含一组的子线程和一组子线程组,线程组是以树形的方式存在,通常情况下根线程组是system线程组。system线程组下是main线程组,默认情况下第一级应用自己的线程组是通过main线程组创建出来的。

基本API介绍

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 构造函数 
ThreadGroup(String name)
ThreadGroup(ThreadGroup parent, String name)

// 基本API
int activeCount() //返回一个预估的当前TreadGroup和子group中存活线程的数量
int activeGroupCount() //返回一个预估的当前TreadGroup所包含的group中存活ThreadGroup的数量
void checkAccess() //判断当前运行的线程是否有权限修改此group
void destroy() //销毁当前group和子group
int enumerate(Thread[] list) //拷贝当前group和子group中的没有dead的线程
int enumerate(Thread[] list,boolean recurs)//和上一个的区别就是是否需要拷贝子group中的线程
int enumerate(ThreadGroup[] list) //拷贝当前group和子group中ThreadGroup
int enumerate(ThreadGroup[] list, boolean recurse) //是否需要子Group
String getName()
ThreadGroup getParent()
void interrupt() //设置当前ThreadGroup中所有的线程中断标记为true
boolean isDaemon()
boolean isDestroyed() //判断当前group是否被销毁
void list() //打印当前group中的信息去标准输入流
boolean parentOf(ThreadGroup g)
void setDaemon(boolean daemon) //改变当前group中的线程为daemon线程
void setMaxPriority(int pri) //设置当前group的权限最大值
int getMaxPriority() //返回当前ThreadGroup的最大权限

void uncaughtException(Thread t, Throwable e)

创建ThreadGroup

简单demo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//创建ThreadGroup
public static void createThreadGroup() {
//获取当前的ThreadGroup
ThreadGroup currentGroup = Thread.currentThread().getThreadGroup();

//定义一个新的ThreadGroup,默认panrent为当前线程所对应的group
ThreadGroup group1 = new ThreadGroup("Group1");

//判断当前线程对应的ThreadGroup是否是group1的parentgroup
System.out.println(currentGroup == group1.getParent());

//定义一个新的group2,其parent为group1
ThreadGroup group2 = new ThreadGroup(group1, "group2");

//使用ThreadGroup自带的API判断group1是否是group2的parent
System.out.println(group1.parentOf(group2));
}

运行结果

1
2
true
true

结果分析:说明如果没有指定创建ThreadGroup的parent,则默认为当前线程所对应的ThreadGroup,另外需要注意的是,ThreadGroup是树形的分布,这课树的根是system,也就是在类加载时就建立好的,接着在main线程启动时,创建了一个以main为名的ThreadGroup。

使用enumerate获取当前thread

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
//使用enumerate 复制Thread
public static void enumerateThread() throws InterruptedException {
//创建一个新的ThreadGroup
ThreadGroup group = new ThreadGroup("group");

//创建线程,设置ThreadGroup
Thread thread = new Thread(group, () - {
while (true) {
try {
TimeUnit.SECONDS.sleep(1);
} catch (Exception e) {
e.printStackTrace();
}
}
});

thread.start();
TimeUnit.MILLISECONDS.sleep(2);

//得到当前线程对应的ThreadGroup
ThreadGroup mainGroup = Thread.currentThread().getThreadGroup();

//创建存储当前ThreadGroup对应线程的数组
Thread[] list = new Thread[mainGroup.activeCount()];

int recuresize = mainGroup.enumerate(list);
System.out.println(recuresize);

recuresize = mainGroup.enumerate(list, false);
System.out.println(recuresize);
}

运行结果:

1
2
2
1

基本API的使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
//一些基本API的操作
public static void testAPI() throws InterruptedException {
//创建一个ThreadGroup
ThreadGroup group = new ThreadGroup("group1");

//创建线程,设置ThreadGroup
Thread thread = new Thread(group, () - {
while (true) {
try {
TimeUnit.SECONDS.sleep(2);
} catch (Exception e) {
e.printStackTrace();
}
}
});
thread.setDaemon(true);
thread.start();


//确保thread开启
TimeUnit.MILLISECONDS.sleep(2);
ThreadGroup mainThreadGroup = Thread.currentThread().getThreadGroup();
System.out.println("activeCount = " + mainThreadGroup.activeCount());
System.out.println("activeGroupCount=" + mainThreadGroup.activeGroupCount());
System.out.println("getMaxPriority = " + mainThreadGroup.getMaxPriority());
System.out.println("getName = " + mainThreadGroup.getName());
System.out.println("getParent = " + mainThreadGroup.getName());
mainThreadGroup.list();
System.out.println("------------------------------------");
System.out.println("parentOf = " + mainThreadGroup.parentOf(group));
System.out.println("parentOf = " + mainThreadGroup.parentOf(mainThreadGroup));

}

运行结果:

1
2
3
4
5
6
7
8
9
10
11
12
activeCount = 2
activeGroupCount=1
getMaxPriority = 10
getName = main
getParent = main
java.lang.ThreadGroup[name=main,maxpri=10]
Thread[main,5,main]
java.lang.ThreadGroup[name=group1,maxpri=10]
Thread[Thread-0,5,group1]
------------------------------------
parentOf = true
parentOf = true

最后需要注意的是,group的parent也可以是自己本身,这不知道是不是bug。

setMaxPriority

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//线程组优先级设置
public static void threadGroupPriority() {
//创建一个ThreadGroup
ThreadGroup group = new ThreadGroup("group1");

//创建线程,设置ThreadGroup
Thread thread = new Thread(group, () - {
while (true) {
try {
TimeUnit.SECONDS.sleep(2);
} catch (Exception e) {
e.printStackTrace();
}
}
});
thread.setDaemon(true);
thread.start();
System.out.println("group getMaxPriority()=" + group.getMaxPriority());
System.out.println("thread.getPriority()=" + thread.getPriority());

//改变group的最大优先级
group.setMaxPriority(3);
System.out.println("group getMaxPriority()=" + group.getMaxPriority());
System.out.println("thread.getPriority()=" + thread.getPriority());
}

运行结果

1
2
3
4
group getMaxPriority()=10
thread.getPriority()=5
group getMaxPriority()=3
thread.getPriority()=5

在ThreadGroup中线程的优先级是不能大于ThreadGroup设置的最大优先级,但是上面的结果显示线程的优先级大于了ThreadGroup的最大优先级。这是因为,线程在添加时优先级是不大于ThreadGroup的最大优先级,但是后来ThreadGroup修改了最大优先级,但由于线程的优先级已经设置好了,ThreadGroup将不能去更改这个优先级,所以就存在线程组中有大于线程组最大优先级的线程。但是在这之后添加的线程就不会大于线程组的优先级。

ThreadGroup的Damon设置和destory

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
//守护ThreadGroup 和destory
public static void threadGroupDaemon() throws InterruptedException {
//创建一个ThreadGroup
ThreadGroup group = new ThreadGroup("group1");

//创建线程,设置ThreadGroup
new Thread(group, () - {

try {
TimeUnit.SECONDS.sleep(1);
} catch (Exception e) {
e.printStackTrace();
}

}, "group1-thread").start();
//创建一个ThreadGroup
ThreadGroup group2 = new ThreadGroup("group2");

//创建线程,设置ThreadGroup
new Thread(group2, () - {

try {
TimeUnit.SECONDS.sleep(1);
} catch (Exception e) {
e.printStackTrace();
}

}, "group2-thread").start();

//设置group2为daemon为true
group2.setDaemon(true);
TimeUnit.SECONDS.sleep(3);
System.out.println(group.isDestroyed());
System.out.println(group2.isDestroyed());
}

运行结果:

1
2
false
true

当线程组设置为daemon之后,只要线程组中不存在活跃的线程,线程组则自动destory。但是如果线程组没有设置daemon为true,即使线程组中没有活跃的线程,也不会自动destory。

注意一点是:destory只有当线程组和子线程组中没有活跃的线程才能调用,否则抛出异常。