我的原则:先会用再说,内部慢慢来。 学以致用,根据场景学源码
文章目录
一、前言1.1 架构1.2 ThreadGroup 能干嘛?1.3 ThreadGroup 常用的方法
二、实战2.1 实战一 :验证 Count2.2 实战二 :验证 Interrupt2.3 实战三 :验证 enumerate2.4 实战四:测试默认 ThreadGroup2.5 实战五:测试 Exception 捕获
三、源码剖析3.1 Class 类初始化3.1.1 demo3.1.2 Thread 构造方法3.1.3 init 方法
3.2 activeCount 方法3.3 activeGroupCount 方法3.4 list 方法3.5 enumerate 方法3.6 interrupt 方法3.7 uncaughtException 方法
四、番外篇
一、前言
1.1 架构
=== 点击查看top目录 ===
1.2 ThreadGroup 能干嘛?
能用来操作group下面的所有线程,比如全部打断 interrupt可以进行链路监控,例如监控某个 group 下面,当前存在多少活跃线程数目。统一捕获该group下线程抛出的异常。
1.3 ThreadGroup 常用的方法
方法描述
int activeCount()查看组内部 thread 活跃数量(包括子group)int activeGroupCount()查看组内部 group 活跃数量(包括子group)void list()打印出group下的所有线程信息(包括子group)void destroy()摧毁线程(包括子group)boolean isDestroyed()查看该 group 有没有被摧毁int enumerate(Thread[] list)copy 某个group 下面的活跃 threadThreadGroup getParent()找爸爸void interrupt()打断这个 group 下面的所有 threadboolean isDaemon()看下是否是幽灵线程void setDaemon(boolean daemon)设置幽灵线程
二、实战
2.1 实战一 :验证 Count
本demo验证了activeCount、activeGroupCount、list、getParent、interrupt 等一系列方法代码流程如下:
创建 group1group1 先创建thread1,2,3 ,由于没start,activeCount得到的的结果是 0thread1,2,3 启动起来(暂时不关闭),activeCount得到的的结果是 3插入 thread4, 启动起来,activeCount得到的的结果是 4thread4 线程跑完,activeCount得到的的结果是 3创建group2(传入 group1)打印出 group2,group1,还有顶级 main 的list信息interrupt 测试打断,诶,虽然main线程跑到最后了,打那是发现scanner.nextLine() 由于内部的死循环while,无法被打断。
public static void testGroupListAndSize() throws Exception
{
ThreadGroup group1
= new ThreadGroup("Group1");
Thread t1
= new Thread(group1
, () -> {
try {
Scanner sc
= new Scanner(System
.in
);
System
.out
.println("点击任意键唤醒线程 ...");
sc
.nextLine();
} catch (Exception e
) {
System
.out
.println("t1 被打断啦 ...");
}
});
Thread t2
= new Thread(group1
, () -> {
try {
Scanner sc
= new Scanner(System
.in
);
System
.out
.println("点击任意键唤醒线程 ...");
sc
.nextLine();
} catch (Exception e
) {
System
.out
.println("t2 被打断啦 ...");
}
});
Thread t3
= new Thread(group1
, () -> {
try {
Scanner sc
= new Scanner(System
.in
);
System
.out
.println("点击任意键唤醒线程 ...");
sc
.nextLine();
} catch (Exception e
) {
System
.out
.println("t3 被打断啦 ...");
}
});
group1
.list();
System
.out
.println("group1.size -> " + group1
.activeCount());
Thread
.sleep(1000);
System
.out
.println("----");
t1
.start();
t2
.start();
t3
.start();
Thread
.sleep(1000);
group1
.list();
System
.out
.println("group1.size -> " + group1
.activeCount());
System
.out
.println("----");
System
.out
.println("==== 启动 thread4,验证 activeCount 含义(只返回活跃数量) ====");
Thread t4
= new Thread(group1
, () -> {
try {
Thread
.sleep(1000);
} catch (InterruptedException e
) {
System
.out
.println("t4 被打断啦 ...");
}
});
t4
.start();
group1
.list();
System
.out
.println("group1.size -> " + group1
.activeCount());
System
.out
.println("----");
Thread
.sleep(2000);
System
.out
.println(" === 2s 后 ,t4 已经down ===");
group1
.list();
System
.out
.println("group1.size -> " + group1
.activeCount());
System
.out
.println("----");
Thread
.sleep(1000);
System
.out
.println("==== 创建子group ====");
ThreadGroup group2
= new ThreadGroup(group1
,"Group2");
Thread t21
= new Thread(group2
, () -> {
try {
Scanner sc
= new Scanner(System
.in
);
System
.out
.println("点击任意键唤醒线程 ...");
sc
.nextLine();
} catch (Exception e
) {
System
.out
.println("t21 被打断啦 ...");
}
});
t21
.start();
Thread
.sleep(1000);
System
.out
.println("遍历下 group1 ,观察是否加入了...");
group1
.list();
System
.out
.println("遍历下 group2 ...");
group2
.list();
System
.out
.println("最后遍历下最牛逼的 group-main ...");
Thread
.currentThread().getThreadGroup().list();
Thread
.sleep(1000);
System
.out
.println("=== 最后打断全部线程 ===");
group1
.interrupt();
System
.out
.println("main thread end ...");
}
输出:
java.lang.ThreadGroup[name=Group1,maxpri=10]
group1.size -> 0
----
点击任意键唤醒线程 ...
点击任意键唤醒线程 ...
点击任意键唤醒线程 ...
java.lang.ThreadGroup[name=Group1,maxpri=10]
Thread[Thread-0,5,Group1]
Thread[Thread-1,5,Group1]
Thread[Thread-2,5,Group1]
group1.size -> 3
----
==== 启动 thread4,验证 activeCount 含义(只返回活跃数量) ====
java.lang.ThreadGroup[name=Group1,maxpri=10]
Thread[Thread-0,5,Group1]
Thread[Thread-1,5,Group1]
Thread[Thread-2,5,Group1]
Thread[Thread-3,5,Group1]
group1.size -> 4
----
=== 2s 后 ,t4 已经down ===
java.lang.ThreadGroup[name=Group1,maxpri=10]
Thread[Thread-0,5,Group1]
Thread[Thread-1,5,Group1]
Thread[Thread-2,5,Group1]
group1.size -> 3
----
==== 创建子group ====
点击任意键唤醒线程 ...
遍历下 group1 ,观察是否加入了...
java.lang.ThreadGroup[name=Group1,maxpri=10]
Thread[Thread-0,5,Group1]
Thread[Thread-1,5,Group1]
Thread[Thread-2,5,Group1]
java.lang.ThreadGroup[name=Group2,maxpri=10]
Thread[Thread-4,5,Group2]
遍历下 group2 ...
java.lang.ThreadGroup[name=Group2,maxpri=10]
Thread[Thread-4,5,Group2]
最后遍历下最牛逼的 group-main ...
java.lang.ThreadGroup[name=main,maxpri=10]
Thread[main,5,main]
Thread[Monitor Ctrl-Break,5,main]
java.lang.ThreadGroup[name=Group1,maxpri=10]
Thread[Thread-0,5,Group1]
Thread[Thread-1,5,Group1]
Thread[Thread-2,5,Group1]
java.lang.ThreadGroup[name=Group2,maxpri=10]
Thread[Thread-4,5,Group2]
=== 最后打断全部线程 ===
main thread end ...
...
注意,这个地方子线程没有中断!!!一直跑着!!!
=== 点击查看top目录 ===
2.2 实战二 :验证 Interrupt
注意,上面这个程序,子线程没有中断!!!一直跑着!!!由于上面有bug,我们重新验证下 interrupt 方法
Thread t1
= new Thread(group1
, () -> {
try {
Thread
.sleep(10000);
} catch (Exception e
) {
System
.out
.println("t1 被打断啦 ...");
}
});
改动一下线程的内部实现,其余地方简化一下
public static void testInterrupte() throws Exception
{
ThreadGroup group1
= new ThreadGroup("Group1");
Thread t1
= new Thread(group1
, () -> {
try {
Thread
.sleep(10000);
} catch (Exception e
) {
System
.out
.println("t1 被打断啦 ...");
}
});
Thread t2
= new Thread(group1
, () -> {
try {
Thread
.sleep(10000);
} catch (Exception e
) {
System
.out
.println("t2 被打断啦 ...");
}
});
Thread t3
= new Thread(group1
, () -> {
try {
Thread
.sleep(10000);
} catch (Exception e
) {
System
.out
.println("t3 被打断啦 ...");
}
});
t1
.start();
t2
.start();
t3
.start();
Thread
.sleep(1000);
group1
.list();
System
.out
.println("group1.size -> " + group1
.activeCount());
System
.out
.println("----");
System
.out
.println("==== 启动 thread4,验证 activeCount 含义(只返回活跃数量) ====");
Thread
.sleep(1000);
System
.out
.println("==== 创建子group ====");
ThreadGroup group2
= new ThreadGroup(group1
,"Group2");
Thread t21
= new Thread(group2
, () -> {
try {
Thread
.sleep(1000);
} catch (Exception e
) {
System
.out
.println("t21 被打断啦 ...");
}
});
t21
.start();
Thread
.sleep(1000);
System
.out
.println("遍历下 group1 ,观察是否加入了...");
group1
.list();
System
.out
.println("遍历下 group2 ...");
group2
.list();
System
.out
.println("最后遍历下最牛逼的 group-main ...");
Thread
.currentThread().getThreadGroup().list();
Thread
.sleep(1000);
System
.out
.println("=== 最后打断全部线程 ===");
group1
.interrupt();
System
.out
.println("main thread end ...");
}
输出:
java.lang.ThreadGroup[name=Group1,maxpri=10]
Thread[Thread-0,5,Group1]
Thread[Thread-1,5,Group1]
Thread[Thread-2,5,Group1]
group1.size -> 3
----
==== 启动 thread4,验证 activeCount 含义(只返回活跃数量) ====
==== 创建子group ====
遍历下 group1 ,观察是否加入了...
java.lang.ThreadGroup[name=Group1,maxpri=10]
Thread[Thread-0,5,Group1]
Thread[Thread-1,5,Group1]
Thread[Thread-2,5,Group1]
java.lang.ThreadGroup[name=Group2,maxpri=10]
Thread[Thread-3,5,Group2]
遍历下 group2 ...
java.lang.ThreadGroup[name=Group2,maxpri=10]
Thread[Thread-3,5,Group2]
最后遍历下最牛逼的 group-main ...
java.lang.ThreadGroup[name=main,maxpri=10]
Thread[main,5,main]
Thread[Monitor Ctrl-Break,5,main]
java.lang.ThreadGroup[name=Group1,maxpri=10]
Thread[Thread-0,5,Group1]
Thread[Thread-1,5,Group1]
Thread[Thread-2,5,Group1]
java.lang.ThreadGroup[name=Group2,maxpri=10]
Thread[Thread-3,5,Group2]
=== 最后打断全部线程 ===
main thread end ...
t1 被打断啦 ...
t2 被打断啦 ...
t3 被打断啦 ...
JVM跑完全程,无任何地方卡住。
=== 点击查看top目录 ===
2.3 实战三 :验证 enumerate
代码流程如下:
测试 enumerate(Thread list[]) ,复制group下面的线程测试 enumerate(ThreadGroup list[]) ,复制整个group测试发现是浅复制
public static void testCopy() throws Exception
{
ThreadGroup group1
= new ThreadGroup("Group1");
System
.out
.println("----");
Thread t1
= new Thread(group1
, () -> {
Scanner sc
= new Scanner(System
.in
);
System
.out
.println("点击任意键唤醒线程 ...");
sc
.nextLine();
});
Thread t2
= new Thread(group1
, () -> {
Scanner sc
= new Scanner(System
.in
);
System
.out
.println("点击任意键唤醒线程 ...");
sc
.nextLine();
});
Thread t3
= new Thread(group1
, () -> {
Scanner sc
= new Scanner(System
.in
);
System
.out
.println("点击任意键唤醒线程 ...");
sc
.nextLine();
});
group1
.list();
System
.out
.println("group1.size -> " + group1
.activeCount());
Thread
.sleep(1000);
System
.out
.println("----");
t1
.start();
t2
.start();
t3
.start();
System
.out
.println("=== 2. begin to copy === ");
Thread
[] threads
= new Thread[group1
.activeCount()];
group1
.enumerate(threads
);
System
.out
.println("group1.size -> " + group1
.activeCount());
System
.out
.println("----");
Arrays
.stream(threads
).forEach(System
.out
::println
);
Thread
.sleep(1000);
System
.out
.println(threads
[0] == t1
);
System
.out
.println(threads
[1] == t2
);
System
.out
.println(threads
[2] == t3
);
System
.out
.println("threads 复制 enumerate 仅仅是浅复制 ...");
System
.out
.println("group1.size -> " + group1
.activeCount());
System
.out
.println("----");
Thread
.sleep(1000);
System
.out
.println("=== 第二波复制 ===");
System
.out
.println("Thread.currentThread().getThreadGroup().activeGroupCount() -> " +
Thread
.currentThread().getThreadGroup().activeGroupCount());
Thread
.currentThread().getThreadGroup().list();
ThreadGroup
[] groups
= new ThreadGroup[Thread
.currentThread().getThreadGroup().activeGroupCount()];
Thread
.currentThread().getThreadGroup().enumerate(groups
);
System
.out
.println("----");
Thread
.sleep(1000);
System
.out
.println("=== 复制完了 ===");
for (ThreadGroup group
:
groups
) {
group
.list();
}
System
.out
.println("groups[0] == group1 ? " + (groups
[0] == group1
));
System
.out
.println("group 复制 enumerate 仅仅是浅复制 ...");
System
.out
.println("group1.size -> " + group1
.activeCount());
System
.out
.println("----");
}
输出:
----
java.lang.ThreadGroup[name=Group1,maxpri=10]
group1.size -> 0
----
=== 2. begin to copy ===
group1.size -> 3
----
Thread[Thread-0,5,Group1]
Thread[Thread-1,5,Group1]
Thread[Thread-2,5,Group1]
点击任意键唤醒线程 ...
点击任意键唤醒线程 ...
点击任意键唤醒线程 ...
true
true
true
enumerate 仅仅是浅复制 ...
group1.size -> 3
----
=== 第二波复制 ===
Thread.currentThread().getThreadGroup().activeGroupCount() -> 1
java.lang.ThreadGroup[name=main,maxpri=10]
Thread[main,5,main]
Thread[Monitor Ctrl-Break,5,main]
java.lang.ThreadGroup[name=Group1,maxpri=10]
Thread[Thread-0,5,Group1]
Thread[Thread-1,5,Group1]
Thread[Thread-2,5,Group1]
----
=== 复制完了 ===
java.lang.ThreadGroup[name=Group1,maxpri=10]
Thread[Thread-0,5,Group1]
Thread[Thread-1,5,Group1]
Thread[Thread-2,5,Group1]
groups[0] == group1 ? true
enumerate 仅仅是浅复制 ...
group1.size -> 3
----
...
(输入任意键,线程结束)
结论:浅层复制,只是引用复制。
=== 点击查看top目录 ===
2.4 实战四:测试默认 ThreadGroup
代码
public static void test01() throws Exception
{
print();
new Thread(() -> print(),"A1").start();
new Thread(() -> new Thread(() -> print(),"B2").start(),"B1").start();
}
public static void print(){
System
.out
.println("currentThread -> " + Thread
.currentThread() + ",group -> " + Thread
.currentThread().getThreadGroup());
}
输出
currentThread
-> Thread
[main
,5,main
],group
-> java
.lang
.ThreadGroup
[name
=main
,maxpri
=10]
currentThread
-> Thread
[A1
,5,main
],group
-> java
.lang
.ThreadGroup
[name
=main
,maxpri
=10]
currentThread
-> Thread
[B2
,5,main
],group
-> java
.lang
.ThreadGroup
[name
=main
,maxpri
=10]
结论: 不指定 group 的情况下,deamon 、priority 参数随父 thread。
=== 点击查看top目录 ===
2.5 实战五:测试 Exception 捕获
代码
public static void testCatchException() throws Exception
{
ThreadGroup g1
= new ThreadGroup("ThreadGroup");
Thread t1
= new Thread(g1
, () -> { throw new RuntimeException(Thread
.currentThread() + "自定义的一个RuntimeException...");});
t1
.start();
Thread
.sleep(1000);
CatchExceptinoThreadGroup g2
= new CatchExceptinoThreadGroup("CatchExceptionThreadGroup");
Thread t2
= new Thread(g2
, () -> { throw new RuntimeException(Thread
.currentThread() + "自定义的一个RuntimeException...");});
t2
.start();
}
public static class CatchExceptinoThreadGroup extends ThreadGroup{
public CatchExceptinoThreadGroup(String name
) {
super(name
);
}
public CatchExceptinoThreadGroup(ThreadGroup parent
, String name
) {
super(parent
, name
);
}
@Override
public void uncaughtException(Thread t
, Throwable e
) {
if(e
instanceof RuntimeException){
System
.out
.println("### CatchExceptinoThreadGroup catch " + e
);
}
}
}
输出
Exception in thread "Thread-0" java.lang.RuntimeException: Thread[Thread-0,5,ThreadGroup]自定义的一个RuntimeException...
at indi.sword.util.basic.Thread._06_01_TestThreadGroup.lambda$testCatchException$15(_06_01_TestThreadGroup.java:291)
at java.lang.Thread.run(Thread.java:748)
### CatchExceptinoThreadGroup catch java.lang.RuntimeException: Thread[Thread-1,5,CatchExceptionThreadGroup]自定义的一个RuntimeException...
解析
g1 线程组(默认组),group内线程抛出异常,无法在外头捕获g2 线程组 (重写组),group内线程抛出异常,被外层捕获到了
结论:可以重写 uncaughtException 方法来进行异常的捕获。关于 Thread.UncaughtExceptionHandler 下一章节进行讲解。
=== 点击查看top目录 ===
三、源码剖析
3.1 Class 类初始化
3.1.1 demo
Thread t1
= new Thread(group1
, () -> {
Scanner sc
= new Scanner(System
.in
);
System
.out
.println("点击任意键唤醒线程 ...");
sc
.nextLine();
});
=== 点击查看top目录 ===
3.1.2 Thread 构造方法
java.lang.Thread#Thread(java.lang.Runnable, java.lang.String)
public Thread(Runnable target
) {
init(null
, target
, "Thread-" + nextThreadNum(), 0);
}
=== 点击查看top目录 ===
3.1.3 init 方法
java.lang.Thread#init(java.lang.ThreadGroup, java.lang.Runnable, java.lang.String, long)
private void init(ThreadGroup g
, Runnable target
, String name
,
long stackSize
) {
init(g
, target
, name
, stackSize
, null
, true);
}
java.lang.Thread#init(java.lang.ThreadGroup, java.lang.Runnable, java.lang.String, long, java.security.AccessControlContext, boolean)
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
) {
if (security
!= null
) {
g
= security
.getThreadGroup();
}
if (g
== null
) {
g
= parent
.getThreadGroup();
}
}
g
.checkAccess();
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
);
this.stackSize
= stackSize
;
tid
= nextThreadID();
}
分析:
若 group 没有指定,那么使用的是父线程的 group ,daemon 与 priority 参数都跟随父类。if (inheritThreadLocals && parent.inheritableThreadLocals != null) 这个具体看上一篇【线程】InheritableThreadLocal 剖析 (十六)
=== 点击查看top目录 ===
3.2 activeCount 方法
java.lang.ThreadGroup#activeCount活跃 thread 数
public int activeCount() {
int result
;
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
;
}
解析:
synchronized 方法块,确保线程安全递归统计。(result = nthreads; // 获取线程数)
=== 点击查看top目录 ===
3.3 activeGroupCount 方法
java.lang.ThreadGroup#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
;
}
解析:
synchronized 方法块,确保线程安全递归统计。(int n = ngroupsSnapshot; // 获取 group 数 )
=== 点击查看top目录 ===
3.4 list 方法
用于打印操作java.lang.ThreadGroup#list()
public void list() {
list(System
.out
, 0);
}
java.lang.ThreadGroup#list(java.io.PrintStream, int) 方法
void list(PrintStream out
, int indent
) {
int ngroupsSnapshot
;
ThreadGroup
[] groupsSnapshot
;
synchronized (this) {
for (int j
= 0 ; j
< indent
; j
++) {
out
.print(" ");
}
out
.println(this);
indent
+= 4;
for (int i
= 0 ; i
< nthreads
; i
++) {
for (int j
= 0 ; j
< indent
; j
++) {
out
.print(" ");
}
out
.println(threads
[i
]);
}
ngroupsSnapshot
= ngroups
;
if (groups
!= null
) {
groupsSnapshot
= Arrays
.copyOf(groups
, ngroupsSnapshot
);
} else {
groupsSnapshot
= null
;
}
}
for (int i
= 0 ; i
< ngroupsSnapshot
; i
++) {
groupsSnapshot
[i
].list(out
, indent
);
}
}
解析:
synchronized 方法块,确保线程安全参数 PrintStream 指定输出流,默认控制台 (System.out,)参数 indent ,打印前置多少个空格,目的是为了层级显示。groupsSnapshot[i].list(out, indent); 递归进行 list 打印操作。
=== 点击查看top目录 ===
3.5 enumerate 方法
java.lang.ThreadGroup#enumerate(java.lang.Thread[])用于复制操作
public int enumerate(Thread list
[]) {
checkAccess();
return enumerate(list
, 0, true);
}
java.lang.ThreadGroup#enumerate(java.lang.Thread[], int, boolean) 方法
private int enumerate(Thread list
[], int n
, boolean recurse
) {
int ngroupsSnapshot
= 0;
ThreadGroup
[] groupsSnapshot
= null
;
synchronized (this) {
if (destroyed
) {
return 0;
}
int nt
= nthreads
;
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);
}
}
return n
;
}
解析:
synchronized 方法块,确保线程安全Arrays.copyOf 进行复制(最终调用Native方法 java.lang.System#arraycopy )groupsSnapshot[i].enumerate(list, n, true); 递归进行复制
=== 点击查看top目录 ===
3.6 interrupt 方法
java.lang.ThreadGroup#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
;
}
}
for (int i
= 0 ; i
< ngroupsSnapshot
; i
++) {
groupsSnapshot
[i
].interrupt();
}
}
解析:
synchronized 方法块,确保线程安全groupsSnapshot[i].interrupt(); 内部递归调用 interrupt
=== 点击查看top目录 ===
3.7 uncaughtException 方法
public void uncaughtException(Thread t
, Throwable e
) {
if (parent
!= null
) {
parent
.uncaughtException(t
, e
);
} else {
Thread
.UncaughtExceptionHandler ueh
=
Thread
.getDefaultUncaughtExceptionHandler();
if (ueh
!= null
) {
ueh
.uncaughtException(t
, e
);
} else if (!(e
instanceof ThreadDeath)) {
System
.err
.print("Exception in thread \""
+ t
.getName() + "\" ");
e
.printStackTrace(System
.err
);
}
}
}
解析:
对于子Thread抛出的Exception,递归交由父 ThreadGroup 定义的 uncaughtException 方法来处理。
四、番外篇
下一章节:【线程】Thread.UncaughtExceptionHandler 实战与剖析 (十八) 上一章节:【线程】InheritableThreadLocal 剖析 (十六)