3.4 ThreadGroup
正如ThreadGroup名字,表示一个线程组,可以将其理解成放一堆线程的容器。当然,ThreadGroup也可以存放其他的线程组。看下官方注释是怎么解释的吧!
* A thread group represents a set of threads. In addition, a thread
* group can also include other thread groups. The thread groups form
* a tree in which every thread group except the initial thread group
* has a parent.
* <p>
* A thread is allowed to access information about its own thread
* group, but not to access information about its thread group's
* parent thread group or any other thread groups.
线程组是树结构,可以容纳线程和线程组,每个线程组都有父节点,除了初始化线程组(可以理解成第一个创建的线程组)。线程可以获取到自己的线程组信息,但是不能获取其他线程组和父线程组信息。
3.4.1 ThreadGroup内部组成
private final ThreadGroup parent;
String name;
int maxPriority;
boolean destroyed;
boolean daemon;
boolean vmAllowSuspension;
int nUnstartedThreads = 0;
int nthreads;
//当前线程组的线程
Thread threads[];
int ngroups;
//树结构
ThreadGroup groups[];
注意线程组里有Thread threads[]表示当前线程组管理的线程,ThreadGroup groups[]表示当前线程组的子线程组。
3.4.2 构造
/**
* 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;
}
空参构造ThreadGroup是一个私有构造方法,是C调用的方法,java无法调用该构造方法,注意system不是主线程所在线程组。
System.err.println(Thread.currentThread().getThreadGroup().getName());
查看当前线程所在线程组,在主线程中查看,可以看到主线程的线程组是main线程组。
3. ThreadGroup添加线程(不建议显示添加)
void add(Thread t) {
synchronized (this) {
if (destroyed) {
throw new IllegalThreadStateException();
}
if (threads == null) {
//null默认4
threads = new Thread[4];
} else if (nthreads == threads.length) {
//扩容线程到原来两倍
threads = Arrays.copyOf(threads, nthreads * 2);
}
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--;
}
}
4. ThreadGroup使用例子
package com.lbh.xxmanager.basic.java;
/**
* Copyright(c)lbhbinhao@163.com
*
* @author liubinhao
* @date 2021/1/30
* ++++ ______ ______ ______
* +++/ /| / /| / /|
* +/_____/ | /_____/ | /_____/ |
* | | | | | | | | |
* | | | | | |________| | |
* | | | | | / | | |
* | | | | |/___________| | |
* | | |___________________ | |____________| | |
* | | / / | | | | | | |
* | |/ _________________/ / | | / | | /
* |_________________________|/b |_____|/ |_____|/
*/
/**
* 1.线程(线程的生命周期) —> 线程的用法(死锁:解决办法(Resource order),资源竞争Race condition)->线程通信(信号量:共享变量,管道就是|符号)
* -> 线程池(ThreadGroup,ThreadLocal)-> 计算机线程(并发)模型 -> JVM(synchronized,volatile)
* 2.并发 并发算法(阻塞和非阻塞) -> JUC(Java.util.concurrent大多数是阻塞)->(java.util:List,Queue,Set,Map)
* ->(cpu底层提供的操作:Atomic) -> JVM(非阻塞的原理)
*/
class MultiThread implements Runnable{
/**
* public default protected private
* @param args
*/
public int item;
public static void main(String[] args) throws InterruptedException {
System.err.println(Thread.currentThread().getThreadGroup().getName());
ThreadGroup threadGroup = new ThreadGroup("groupName");
Thread thread = new Thread(threadGroup,new MultiThread());
thread.start();
Thread.sleep(100);
System.err.println(threadGroup.activeCount());
System.err.println(threadGroup);
}
@Override
public void run() {
System.err.println(Thread.currentThread());
for (int i=0;i<5;i++){
new Thread(()->{
System.err.println(Thread.currentThread());
while (true){
//doNothing
}
}
).start();
}
while(true){
//doNothing
}
}
}
ThreadGroup threadGroup = new ThreadGroup("groupName");
Thread thread = new Thread(threadGroup,new MultiThread());
只往线程组中添加了一个创建的线程,但是最后线程组中却有6个,这是为什么呢?
答案:当前线程创建的子线程会附加到当前线程的线程组,看源码(Thread类下)。
private void init(ThreadGroup g, Runnable target, String name,
long stackSize, AccessControlContext acc,
boolean inheritThreadLocals) {
if (name == null) {
throw new NullPointerException("name cannot be null");
}
this.name = name;
Thread parent = currentThread();
SecurityManager security = System.getSecurityManager();
if (g == null) {
/* Determine if it's an applet or not */
/* If there is a security manager, ask the security manager
what to do. */
if (security != null) {
g = security.getThreadGroup();
}
/* If the security doesn't have a strong opinion of the matter
use the parent thread group. */
if (g == null) {
g = parent.getThreadGroup();
}
}
/* checkAccess regardless of whether or not threadgroup is
explicitly passed in. */
g.checkAccess();
/*
* Do we have the required permissions?
*/
if (security != null) {
if (isCCLOverridden(getClass())) {
security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
}
}
g.addUnstarted();
this.group = g;
this.daemon = parent.isDaemon();
this.priority = parent.getPriority();
if (security == null || isCCLOverridden(parent.getClass()))
this.contextClassLoader = parent.getContextClassLoader();
else
this.contextClassLoader = parent.contextClassLoader;
this.inheritedAccessControlContext =
acc != null ? acc : AccessController.getContext();
this.target = target;
setPriority(priority);
if (inheritThreadLocals && parent.inheritableThreadLocals != null)
this.inheritableThreadLocals =
ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
/* Stash the specified stack size in case the VM cares */
this.stackSize = stackSize;
/* Set thread ID */
tid = nextThreadID();
}
/* If the security doesn't have a strong opinion of the matter
use the parent thread group. */
if (g == null) {
g = parent.getThreadGroup();
}
注意上边一段代码,构造传入的线程组为null时,获取到创建该线程的线程组,也就是说子线程会附加到创建该线程的线程组上。关于线程组还有很多用法,笔者就在此仅作抛砖引玉,欢迎与笔者讨论。