java ThreadGroup源码分析
使用:
import javax.swing.text.html.HTMLDocument.HTMLReader.IsindexAction; public class Test { public static void main(String[] args) { ThreadGroup tg = new ThreadGroup("threadGroup-001"); Thread t1 = new Thread(tg, new MyThread());
t1.start(); Thread t2 = new Thread(tg, new MyThread());
t2.start(); // 返回线程组中活动线程的估计数
System.out.println("active thread group: " + tg.activeCount());
// 返回此线程组中活动线程组的估计数
System.out.println("activeGroupCount: " + tg.activeGroupCount());
// 检查当前运行的线程是否有权修改此线程组
tg.checkAccess();
// 设置线程组的最高优先级
tg.setMaxPriority(6);
// 返回此线程组的最高优先级
System.out.println("maxPriority: " + tg.getMaxPriority());
// 返回此线程组的名称
System.out.println("thread group name: " + tg.getName());
// 返回此线程组的父线程组
System.out.println(tg.getParent());
// 中断此线程组中的所有线程
tg.interrupt();
// 更改此线程组的后台程序状态
tg.setDaemon(true);
// 测试此线程组是否为一个后台程序线程组
System.out.println("is daemon: " + tg.isDaemon());
// 测试此线程组是否为线程组参数或其祖先线程组之一
System.out.println("is parent: "+ tg.getParent().parentOf(tg));
// 打印线程组信息
tg.list();
// 返回线程组的字符串表示形式
System.out.println(tg.toString());
// 销毁此线程组及其所有子组
tg.destroy();
// 测试此线程组是否已经销毁
System.out.println(tg.isDestroyed());
// System.out.println(tg.);
} private static class MyThread extends Thread {
@Override
public void run() {
System.out.println("thread name: " + Thread.currentThread().getName());
}
} }
一、构造函数
两种构造函数:
ThreadGroup(String name) ThreadGroup(ThreadGroup parent, String name)
public ThreadGroup(String name) {
this(Thread.currentThread().getThreadGroup(), name);
}
public ThreadGroup(ThreadGroup parent, String name) {
this(checkParentAccess(parent), parent, name);
}
private ThreadGroup(Void unused, ThreadGroup parent, String name) {
this.name = name;
this.maxPriority = parent.maxPriority;
this.daemon = parent.daemon;
this.parent = parent;
parent.add(this);
}
private final void add(ThreadGroup g){
synchronized (this) {
if (destroyed) {
throw new IllegalThreadStateException();
}
// 添加一个线程组到此线程组的groups数组中,groups初始容量为4,每次容量耗尽之后按2倍扩增。
if (groups == null) {
groups = new ThreadGroup[4];
} else if (ngroups == groups.length) {
groups = Arrays.copyOf(groups, ngroups * 2);
}
groups[ngroups] = g; // This is done last so it doesn't matter in case the
// thread is killed
ngroups++;
}
}
二、添加线程到线程组
ThreadGroup tg = new ThreadGroup("threadGroup-001");
Thread t1 = new Thread(tg, new MyThread());
t1.start();
new Thread(tg, new MyThread()); 调用后,关于线程组相关的操作设置可在 private Thread(ThreadGroup g, Runnable target, String name,long stackSize, AccessControlContext acc,boolean inheritThreadLocals)看到:
private Thread(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 manager doesn't have a strong opinion
on 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(
SecurityConstants.SUBCLASS_IMPLEMENTATION_PERMISSION);
}
} // 调用类ThreadGroup的addUnstarted函数, 添加一个未启用的线程到线程组
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 */
this.tid = nextThreadID();
}
主要操作:设置此线程的线程组,将线程组的未启动线程数加1(addUnstarted() 即nUnstartedThreads++)。
随后启动一个线程(t1.start()):
public synchronized void start() {
/**
* This method is not invoked for the main method thread or "system"
* group threads created/set up by the VM. Any new functionality added
* to this method in the future may have to also be added to the VM.
*
* A zero status value corresponds to state "NEW".
*/
if (threadStatus != 0)
throw new IllegalThreadStateException(); /* Notify the group that this thread is about to be started
* so that it can be added to the group's list of threads
* and the group's unstarted count can be decremented. */
group.add(this); boolean started = false;
try {
start0();
started = true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
/* do nothing. If start0 threw a Throwable then
it will be passed up the call stack */
}
}
}
start()中的先调用 group.add(this)。然后线程启动失败后调用 group.threadStartFailed(this) 。
源码如下:
void add(Thread t) {
synchronized (this) {
if (destroyed) {
throw new IllegalThreadStateException();
}
// ThreadGroup维护了一个数组,用来存放线程。
if (threads == null) {
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
// 线程数组中线程数量增加1
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.
// 未启动线程数减1
nUnstartedThreads--;
}
}
void threadStartFailed(Thread t) {
synchronized(this) {
// 线程组中移除线程t
remove(t);
// 未启动线程数增加1
nUnstartedThreads++;
}
}
private void remove(Thread t) {
synchronized (this) {
if (destroyed) {
return;
}
// 循环遍历查找线程t,并移除
for (int i = 0 ; i < nthreads ; i++) {
if (threads[i] == t) {
System.arraycopy(threads, i + 1, threads, i, --nthreads - i);
// Zap dangling reference to the dead thread so that
// the garbage collector will collect it.
threads[nthreads] = null;
break;
}
}
}
}
由上可见:只有调用start()成功启动的线程才会被它的线程组保存。
三、ThreadGroup的一些函数
1、destory() 销毁此线程组及其所有子组
// 销毁此线程组及其所有子线程组
public final void destroy() {
int ngroupsSnapshot;
ThreadGroup[] groupsSnapshot;
synchronized (this) {
checkAccess();
if (destroyed || (nthreads > 0)) {
throw new IllegalThreadStateException();
}
// 子线程组数量
ngroupsSnapshot = ngroups;
// 子线程组数组
if (groups != null) {
groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
} else {
groupsSnapshot = null;
}
// 置空子线程数量、子线程组、子线程组数量、子线程组数组
if (parent != null) {
destroyed = true;
ngroups = 0;
groups = null;
nthreads = 0;
threads = null;
}
}
// 递归子线程组
for (int i = 0 ; i < ngroupsSnapshot ; i += 1) {
groupsSnapshot[i].destroy();
}
// 从父线程组中移除此线程组
if (parent != null) {
parent.remove(this);
}
}
2、interrupt() 中断此线程组中的所有线程(包括子线程组中的线程)
// 中断此线程组中的所有线程(包括子线程组中的线程)
public final void interrupt() {
int ngroupsSnapshot;
ThreadGroup[] groupsSnapshot;
synchronized (this) {
checkAccess();
// 循环遍历线程组中的子线程,中断线程
for (int i = 0 ; i < nthreads ; i++) {
threads[i].interrupt();
}
ngroupsSnapshot = ngroups;
if (groups != null) {
groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
} else {
groupsSnapshot = null;
}
}
// 递归去子线程组执行interrupt()
for (int i = 0 ; i < ngroupsSnapshot ; i++) {
groupsSnapshot[i].interrupt();
}
}
3、setMaxPriority 设置线程组(包括子线程组)的最高优先级
// 设置线程组(包括子线程组)的最高优先级
public final void setMaxPriority(int pri) {
int ngroupsSnapshot;
ThreadGroup[] groupsSnapshot;
synchronized (this) {
checkAccess();
// 检验优先级大小是否合规
if (pri < Thread.MIN_PRIORITY || pri > Thread.MAX_PRIORITY) {
return;
}
// 最高优先级不能大于父线程组
maxPriority = (parent != null) ? Math.min(pri, parent.maxPriority) : pri;
ngroupsSnapshot = ngroups;
if (groups != null) {
groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
} else {
groupsSnapshot = null;
}
}
// 递归设置子线程组的最高优先级
for (int i = 0 ; i < ngroupsSnapshot ; i++) {
groupsSnapshot[i].setMaxPriority(pri);
}
}
4、parentOf 判断是否为当前线程组的祖先线程组(或是否是当前线程组)
// 判断g是否为当前线程组的祖先线程组(或是否是当前线程组)
public final boolean parentOf(ThreadGroup g) {
// 向上查找父线程组,直到父线程组为空,判断g是否为当前线程组的祖先线程组(或是否是当前线程组)
for (; g != null ; g = g.parent) {
if (g == this) {
return true;
}
}
return false;
}
5、activeCount 返回线程组中活动线程的估计数
// 返回线程组中活动线程的估计数
public int activeCount() {
int result;
// Snapshot sub-group data so we don't hold this lock
// while our children are computing.
int ngroupsSnapshot;
ThreadGroup[] groupsSnapshot;
synchronized (this) {
if (destroyed) {
return 0;
}
// 线程组中的线程数
result = nthreads;
// 子线程组
ngroupsSnapshot = ngroups;
if (groups != null) {
groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
} else {
groupsSnapshot = null;
}
}
// 递归子孙线程组
for (int i = 0 ; i < ngroupsSnapshot ; i++) {
result += groupsSnapshot[i].activeCount();
}
return result;
}
6、activeGroupCount 返回此线程组中活动线程组的估计数
public int activeGroupCount() {
int ngroupsSnapshot;
ThreadGroup[] groupsSnapshot;
synchronized (this) {
if (destroyed) {
return 0;
}
// 子线程组数量
ngroupsSnapshot = ngroups;
if (groups != null) {
groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
} else {
groupsSnapshot = null;
}
}
int n = ngroupsSnapshot;
// 递归子孙线程组
for (int i = 0 ; i < ngroupsSnapshot ; i++) {
n += groupsSnapshot[i].activeGroupCount();
}
return n;
}
7、enumerate 所有活动线程复制到指定数组中
// rescurse 否还包括作为此线程组的子组的线程组中的线程。
// n 是list中已经存在的元素(线程)数量
private int enumerate(Thread list[], int n, boolean recurse) {
int ngroupsSnapshot = 0;
ThreadGroup[] groupsSnapshot = null;
synchronized (this) {
if (destroyed) {
return 0;
}
// 线程组中的线程
int nt = nthreads;
// nt不能大于list的可用长度(递归遍历子孙线程组的时候,会带上n,所以此处要减去n)
if (nt > list.length - n) {
nt = list.length - n;
}
for (int i = 0; i < nt; i++) {
if (threads[i].isAlive()) {
list[n++] = threads[i];
}
}
// 子孙线程组
if (recurse) {
ngroupsSnapshot = ngroups;
if (groups != null) {
groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
} else {
groupsSnapshot = null;
}
}
}
// 递归子孙线程组
if (recurse) {
for (int i = 0 ; i < ngroupsSnapshot ; i++) {
n = groupsSnapshot[i].enumerate(list, n, true);
}
}
// 返回已添加到list的线程数量
return n;
}
java ThreadGroup源码分析的更多相关文章
- Java Reference 源码分析
@(Java)[Reference] Java Reference 源码分析 Reference对象封装了其它对象的引用,可以和普通的对象一样操作,在一定的限制条件下,支持和垃圾收集器的交互.即可以使 ...
- Java 集合源码分析(一)HashMap
目录 Java 集合源码分析(一)HashMap 1. 概要 2. JDK 7 的 HashMap 3. JDK 1.8 的 HashMap 4. Hashtable 5. JDK 1.7 的 Con ...
- java集合源码分析(三):ArrayList
概述 在前文:java集合源码分析(二):List与AbstractList 和 java集合源码分析(一):Collection 与 AbstractCollection 中,我们大致了解了从 Co ...
- java集合源码分析(六):HashMap
概述 HashMap 是 Map 接口下一个线程不安全的,基于哈希表的实现类.由于他解决哈希冲突的方式是分离链表法,也就是拉链法,因此他的数据结构是数组+链表,在 JDK8 以后,当哈希冲突严重时,H ...
- Java集合源码分析(六)TreeSet<E>
TreeSet简介 TreeSet 是一个有序的集合,它的作用是提供有序的Set集合.它继承于AbstractSet抽象类,实现了NavigableSet<E>, Cloneable, j ...
- Java集合源码分析(五)HashSet<E>
HashSet简介 HashSet实现Set接口,由哈希表(实际上是一个HashMap实例)支持.它不保证set 的迭代顺序:特别是它不保证该顺序恒久不变.此类允许使用null元素. HashSet源 ...
- Java集合源码分析(四)Vector<E>
Vector<E>简介 Vector也是基于数组实现的,是一个动态数组,其容量能自动增长. Vector是JDK1.0引入了,它的很多实现方法都加入了同步语句,因此是线程安全的(其实也只是 ...
- Java集合源码分析(三)LinkedList
LinkedList简介 LinkedList是基于双向循环链表(从源码中可以很容易看出)实现的,除了可以当做链表来操作外,它还可以当做栈.队列和双端队列来使用. LinkedList同样是非线程安全 ...
- Java集合源码分析(二)ArrayList
ArrayList简介 ArrayList是基于数组实现的,是一个动态数组,其容量能自动增长,类似于C语言中的动态申请内存,动态增长内存. ArrayList不是线程安全的,只能用在单线程环境下,多线 ...
随机推荐
- List of Mozilla-Based Applications
List of Mozilla-Based Applications The following is a list of all known active applications that are ...
- .net sqlite 内存溢出 问题的分析与解决。
一个小的工具网站,用了sqlite数据库,在并发小的情况一切正常,但是并发量上来之后,就报"out of memory"错误了. 分析了代码,就是很简单的根据一个条件取一段数据,并 ...
- sed扩展命令使用
[root@b ~]# cat f.txt inet addr:192.168.0.110 Bcast:192.168.0.255 Mask:255.255.255.0[root@b ~]# cat ...
- maven 插件的应用
在pom.xml里配置 以测试插件介绍为主 <build> <plugins> <plugin> <groupId>org.apache.maven.p ...
- 在windows下使用Mingw搭建模拟Linux
1.到官网下载最新版Mingw 2.点击安装,最好选择默认路径,如果不是的话,路径中一定不能有空格. 3.选择安装,mingw-developer-toolkit.mingw32-base.mingw ...
- echars 柱状图正常状态 --》二次封装
<template> <!-- 柱状图 正常 1. 调用页面引入 import EcharsColumnNormal from '@/components/echarsColumnN ...
- 这款多线程中间件,吊打 Redis!
Java技术栈 www.javastack.cn 优秀的Java技术公众号 今天给大家介绍的是KeyDB,KeyDB项目是从redis fork出来的分支.众所周知redis是一个单线程的kv内存存储 ...
- ENGINE=InnoDB AUTO_INCREMENT=22 DEFAULT CHARSET=utf8;
参考来源:https://blog.csdn.net/yuxinha11/article/details/80090197 ENGINE=InnoDB不是默认就是这个引擎吗?——是的,如果不写也是ok ...
- D-多连块拼图
多连块是指由多个等大正方形边与边连接而成的平面连通图形. – 维基百科 给一个大多连块和小多连块,你的任务是判断大多连块是否可以由两个这样的小多连块拼成.小多连块只能平移,不能旋转或者翻转.两个小多连 ...
- Tabcontrol动态添加TabPage(获取或设置当前选项卡及其属性)
http://blog.csdn.net/xiongxyt2/article/details/6920575 •MultiLine 属性用true 或false来确定是否可以多行显示 •Appeara ...