一、简介
我们以前一直说线程,但是其实线程有这么一个构造函数,我们看一下。
public Thread(ThreadGroup group, Runnable target, String name) {
init(group, target, name, 0);
}
我们看到第一个参数是分组,其实就是线程组,这里引出线程组的概念,也就是说我们能给那些线程分组,使得多个线程处于一个组下面,方便管理。我们来看看线程组的一个结构图。
我们看到他是个树状的结构,而且每个下面都可以有线程和线程组,我没画全,其实是还能有很多层,每个节点下面都能有。
这就是线程组的一个结构,我们来看下代码、
二、线程组的源码
1、构造方法
public Thread(ThreadGroup group, Runnable target, String name) {
init(group, target, name, 0);
}
我们点进去init这个方法。
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();
}
到这里我们基本知道了这个线程组的一个设计。你指定了就是你指定的,没指定就按父线程的线程组进行处理。
2、代码操作
package com.lyx.thread;
import java.util.concurrent.TimeUnit;
/**
* @author: levi
* @description: TODO
* @date: 2022-10-10 21:10
* @version: 1.0
*/
public class ThreadGroupApi {
public static void main(String[] args) {
// 1号线程组
ThreadGroup group1 = new ThreadGroup("group1");
// 2号线程组,但是2号线程组属于1号线程组,我把线程组1作为参数传进去
ThreadGroup group2 = new ThreadGroup(group1,"group2");
// t11属于线程组1
Thread t11 = new Thread(group1,()->{
System.out.println(Thread.currentThread().getName() + "is running...");
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
},"t11");
// t12属于线程组1
Thread t12 = new Thread(group1,()->{
System.out.println(Thread.currentThread().getName() + "is running...");
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
},"t12");
// t13属于线程组1
Thread t13 = new Thread(group1,()->{
System.out.println(Thread.currentThread().getName() + "is running...");
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
},"t13");
// t14不指定线程组
Thread t14 = new Thread(()->{
System.out.println(Thread.currentThread().getName() + "is running...");
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
},"t14");
// t21属于线程组2
Thread t21 = new Thread(group2,()->{
System.out.println(Thread.currentThread().getName() + "is running...");
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
},"t21");
// t22属于线程组2
Thread t22 = new Thread(group2,()->{
System.out.println(Thread.currentThread().getName() + "is running...");
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
},"t22");
t11.start();
t12.start();
t13.start();
//t14.start();
t21.start();
t22.start();
System.out.println("t11所属线程组为:" + t11.getThreadGroup().getName());
System.out.println("t12所属线程组为:" + t12.getThreadGroup().getName());
System.out.println("t13所属线程组为:" + t13.getThreadGroup().getName());
System.out.println("t14所属线程组为:" + t14.getThreadGroup().getName());
System.out.println("t21所属线程组为:" + t21.getThreadGroup().getName());
System.out.println("t22所属线程组为:" + t22.getThreadGroup().getName());
System.out.println("main线程所属线程组为:" + Thread.currentThread().getThreadGroup().getName());
System.out.println("1号线程组里面活跃的线程个数为:" + t11.getThreadGroup().activeCount());
System.out.println("1号线程组里面活跃的线程组个数为:" + t11.getThreadGroup().activeGroupCount());
System.out.println("main线程组里面活跃的线程个数为:" + Thread.currentThread().getThreadGroup().activeCount());
System.out.println("main线程组里面活跃的线程组个数为:" + Thread.currentThread().getThreadGroup().activeGroupCount());
}
}
1号线程组
2号线程组,但是2号线程组属于1号线程组,我把线程组1作为参数传进去
t11属于线程组1
t12属于线程组1
t13属于线程组1
t14不指定线程组
t21属于线程组2
t22属于线程组2
t11.start();
t12.start();
t13.start();
//t14.start();
t21.start();
t22.start();
经过上面的描述我们基本可以得到一个关系图如下:
所以我们看下运行结果是不是能对的上:
t13is running...
t12is running...
t11所属线程组为:group1
t11is running...
t12所属线程组为:group1
t22is running...
t13所属线程组为:group1
t21is running...
t14所属线程组为:main t14没指定所以是父线程组,t14在主线程开的线程,所以父线程就是main
t21所属线程组为:group2
t22所属线程组为:group2
main线程所属线程组为:main
1号线程组里面活跃的线程个数为:5 1号线程组里面有五个启动的,要是有一个没start就会少一个
1号线程组里面活跃的线程组个数为:1
main线程组里面活跃的线程个数为:6 我们启动了五个线程,包括主线程是6个
main线程组里面活跃的线程组个数为:2
本文未完待续。。。