Concurrency: Basic Threading (3)
Author: nex3z
2016-06-30
9. Coding variations
9.1. 直接继承Thread
创建任务除了通过实现Runnable
接口,也可以通过直接继承Thread
的方式来实现。
public class SimpleThread extends Thread {
private int countDown = 5;
private static int threadCount = 0;
// Store the thread name:
super(Integer.toString(++threadCount));
public String toString() {
return "#" + getName() + "(" + countDown + "), ";
public static void main(String[] args) {
for(int i = 0; i < 5; i++)
#1(5), #4(5), #4(4), #4(3), #5(5), #2(5), #3(5), #2(4), #2(3), #2(2), #2(1), #5(4),
#4(2), #4(1), #1(4), #5(3), #3(4), #5(2), #1(3), #5(1), #3(3), #3(2), #3(1), #1(2),
public class SimpleThread extends Thread {
private int countDown = 5;
private static int threadCount = 0;
public SimpleThread() {
// Store the thread name:
super(Integer.toString(++threadCount));
start();
}
public String toString() {
return "#" + getName() + "(" + countDown + "), ";
}
public void run() {
while(true) {
System.out.print(this);
if(--countDown == 0)
return;
}
}
public static void main(String[] args) {
for(int i = 0; i < 5; i++)
new SimpleThread();
}
}
/* Output
#1(5), #4(5), #4(4), #4(3), #5(5), #2(5), #3(5), #2(4), #2(3), #2(2), #2(1), #5(4),
#4(2), #4(1), #1(4), #5(3), #3(4), #5(2), #1(3), #5(1), #3(3), #3(2), #3(1), #1(2),
#1(1),
*/
public class SimpleThread extends Thread {
private int countDown = 5;
private static int threadCount = 0;
public SimpleThread() {
// Store the thread name:
super(Integer.toString(++threadCount));
start();
}
public String toString() {
return "#" + getName() + "(" + countDown + "), ";
}
public void run() {
while(true) {
System.out.print(this);
if(--countDown == 0)
return;
}
}
public static void main(String[] args) {
for(int i = 0; i < 5; i++)
new SimpleThread();
}
}
/* Output
#1(5), #4(5), #4(4), #4(3), #5(5), #2(5), #3(5), #2(4), #2(3), #2(2), #2(1), #5(4),
#4(2), #4(1), #1(4), #5(3), #3(4), #5(2), #1(3), #5(1), #3(3), #3(2), #3(1), #1(2),
#1(1),
*/
9.2. 自管理Runnable
还有一种自管理Runnable
的用法,由实现Runnable
的类自己创建并开始线程。
public class SelfManaged implements Runnable {
private int countDown = 5;
private Thread t = new Thread(this);
public SelfManaged() { t.start(); }
public String toString() {
return Thread.currentThread().getName() + "(" + countDown + "), ";
public static void main(String[] args) {
for(int i = 0; i < 5; i++)
Thread-0(5), Thread-4(5), Thread-3(5), Thread-2(5), Thread-1(5), Thread-2(4),
Thread-3(4), Thread-4(4), Thread-0(4), Thread-4(3), Thread-3(3), Thread-2(3),
Thread-1(4), Thread-2(2), Thread-3(2), Thread-4(2), Thread-0(3), Thread-4(1),
Thread-3(1), Thread-2(1), Thread-1(3), Thread-1(2), Thread-0(2), Thread-1(1),
public class SelfManaged implements Runnable {
private int countDown = 5;
private Thread t = new Thread(this);
public SelfManaged() { t.start(); }
public String toString() {
return Thread.currentThread().getName() + "(" + countDown + "), ";
}
public void run() {
while(true) {
System.out.print(this);
if(--countDown == 0)
return;
}
}
public static void main(String[] args) {
for(int i = 0; i < 5; i++)
new SelfManaged();
}
}
/* Output
Thread-0(5), Thread-4(5), Thread-3(5), Thread-2(5), Thread-1(5), Thread-2(4),
Thread-3(4), Thread-4(4), Thread-0(4), Thread-4(3), Thread-3(3), Thread-2(3),
Thread-1(4), Thread-2(2), Thread-3(2), Thread-4(2), Thread-0(3), Thread-4(1),
Thread-3(1), Thread-2(1), Thread-1(3), Thread-1(2), Thread-0(2), Thread-1(1),
Thread-0(1),
*/
public class SelfManaged implements Runnable {
private int countDown = 5;
private Thread t = new Thread(this);
public SelfManaged() { t.start(); }
public String toString() {
return Thread.currentThread().getName() + "(" + countDown + "), ";
}
public void run() {
while(true) {
System.out.print(this);
if(--countDown == 0)
return;
}
}
public static void main(String[] args) {
for(int i = 0; i < 5; i++)
new SelfManaged();
}
}
/* Output
Thread-0(5), Thread-4(5), Thread-3(5), Thread-2(5), Thread-1(5), Thread-2(4),
Thread-3(4), Thread-4(4), Thread-0(4), Thread-4(3), Thread-3(3), Thread-2(3),
Thread-1(4), Thread-2(2), Thread-3(2), Thread-4(2), Thread-0(3), Thread-4(1),
Thread-3(1), Thread-2(1), Thread-1(3), Thread-1(2), Thread-0(2), Thread-1(1),
Thread-0(1),
*/
通过实现Runnable
来创建任务的好处是,可以同时继承其他类。
上面的两个简单的例子都在构造器中调用start()
开始线程。对于更加复杂的情况,在构造器中调用start()
可能会带来问题:调用start()
时任务已经在新的线程上开始执行,但构造器可能还没有执行结束,这时任务就有可能访问还没有初始化完成的资源。应尽量使用Executors
而不要手动创建Thread
。
9.3. 内部类继承Thread
使用内部类继承Thread
的方式,可以在任务中访问外部成员。
private int countDown = 5;
private class Inner extends Thread {
System.out.println(this);
if(--countDown == 0) return;
} catch(InterruptedException e) {
System.out.println("interrupted");
public String toString() {
return getName() + ": " + countDown;
public InnerThread1(String name) {
class InnerThread1 {
private int countDown = 5;
private Inner inner;
private class Inner extends Thread {
Inner(String name) {
super(name);
start();
}
public void run() {
try {
while(true) {
System.out.println(this);
if(--countDown == 0) return;
sleep(10);
}
} catch(InterruptedException e) {
System.out.println("interrupted");
}
}
public String toString() {
return getName() + ": " + countDown;
}
}
public InnerThread1(String name) {
inner = new Inner(name);
}
}
class InnerThread1 {
private int countDown = 5;
private Inner inner;
private class Inner extends Thread {
Inner(String name) {
super(name);
start();
}
public void run() {
try {
while(true) {
System.out.println(this);
if(--countDown == 0) return;
sleep(10);
}
} catch(InterruptedException e) {
System.out.println("interrupted");
}
}
public String toString() {
return getName() + ": " + countDown;
}
}
public InnerThread1(String name) {
inner = new Inner(name);
}
}
这里InnerThread1
的内部类Inner
继承Thread
,在其run()
中可以访问InnerThread1
的countDown
。
9.4. 匿名内部类继承Thread
如果只是为了获得多线程的能力,继承Thread
的内部类的名字并不重要,可以使用匿名内部类。
private int countDown = 5;
public InnerThread2(String name) {
System.out.println(this);
if(--countDown == 0) return;
} catch(InterruptedException e) {
System.out.println("sleep() interrupted");
public String toString() {
return getName() + ": " + countDown;
class InnerThread2 {
private int countDown = 5;
private Thread t;
public InnerThread2(String name) {
t = new Thread(name) {
public void run() {
try {
while(true) {
System.out.println(this);
if(--countDown == 0) return;
sleep(10);
}
} catch(InterruptedException e) {
System.out.println("sleep() interrupted");
}
}
public String toString() {
return getName() + ": " + countDown;
}
};
t.start();
}
}
class InnerThread2 {
private int countDown = 5;
private Thread t;
public InnerThread2(String name) {
t = new Thread(name) {
public void run() {
try {
while(true) {
System.out.println(this);
if(--countDown == 0) return;
sleep(10);
}
} catch(InterruptedException e) {
System.out.println("sleep() interrupted");
}
}
public String toString() {
return getName() + ": " + countDown;
}
};
t.start();
}
}
9.5. 内部类实现Runnable
下面的InnerRunnable1
使用内部类实现Runnable
。
import java.util.concurrent.TimeUnit;
private int countDown = 5;
private class Inner implements Runnable {
t = new Thread(this, name);
System.out.println(this);
if(--countDown == 0) return;
TimeUnit.MILLISECONDS.sleep(10);
} catch(InterruptedException e) {
System.out.println("sleep() interrupted");
public String toString() {
return t.getName() + ": " + countDown;
public InnerRunnable1(String name) {
import java.util.concurrent.TimeUnit;
class InnerRunnable1 {
private int countDown = 5;
private Inner inner;
private class Inner implements Runnable {
Thread t;
Inner(String name) {
t = new Thread(this, name);
t.start();
}
public void run() {
try {
while(true) {
System.out.println(this);
if(--countDown == 0) return;
TimeUnit.MILLISECONDS.sleep(10);
}
} catch(InterruptedException e) {
System.out.println("sleep() interrupted");
}
}
public String toString() {
return t.getName() + ": " + countDown;
}
}
public InnerRunnable1(String name) {
inner = new Inner(name);
}
}
import java.util.concurrent.TimeUnit;
class InnerRunnable1 {
private int countDown = 5;
private Inner inner;
private class Inner implements Runnable {
Thread t;
Inner(String name) {
t = new Thread(this, name);
t.start();
}
public void run() {
try {
while(true) {
System.out.println(this);
if(--countDown == 0) return;
TimeUnit.MILLISECONDS.sleep(10);
}
} catch(InterruptedException e) {
System.out.println("sleep() interrupted");
}
}
public String toString() {
return t.getName() + ": " + countDown;
}
}
public InnerRunnable1(String name) {
inner = new Inner(name);
}
}
9.6. 匿名内部类实现Runnable
下面的InnerRunnable2
使用匿名内部类实现Runnable
。
import java.util.concurrent.TimeUnit;
private int countDown = 5;
public InnerRunnable2(String name) {
t = new Thread(new Runnable() {
System.out.println(this);
if(--countDown == 0) return;
TimeUnit.MILLISECONDS.sleep(10);
} catch(InterruptedException e) {
System.out.println("sleep() interrupted");
public String toString() {
return Thread.currentThread().getName() + ": " + countDown;
import java.util.concurrent.TimeUnit;
class InnerRunnable2 {
private int countDown = 5;
private Thread t;
public InnerRunnable2(String name) {
t = new Thread(new Runnable() {
public void run() {
try {
while(true) {
System.out.println(this);
if(--countDown == 0) return;
TimeUnit.MILLISECONDS.sleep(10);
}
} catch(InterruptedException e) {
System.out.println("sleep() interrupted");
}
}
public String toString() {
return Thread.currentThread().getName() + ": " + countDown;
}
}, name);
t.start();
}
}
import java.util.concurrent.TimeUnit;
class InnerRunnable2 {
private int countDown = 5;
private Thread t;
public InnerRunnable2(String name) {
t = new Thread(new Runnable() {
public void run() {
try {
while(true) {
System.out.println(this);
if(--countDown == 0) return;
TimeUnit.MILLISECONDS.sleep(10);
}
} catch(InterruptedException e) {
System.out.println("sleep() interrupted");
}
}
public String toString() {
return Thread.currentThread().getName() + ": " + countDown;
}
}, name);
t.start();
}
}
9.7. 在方法内创建线程
下面的ThreadMethod
在runTask()
中创建并并开始线程。如果创建线程只是为了做一些辅助性的工作,这种方式比在构造器中创建并开始线程更加合适。
private int countDown = 5;
public ThreadMethod(String name) { this.name = name; }
System.out.println(this);
if(--countDown == 0) return;
} catch(InterruptedException e) {
System.out.println("sleep() interrupted");
public String toString() {
return getName() + ": " + countDown;
class ThreadMethod {
private int countDown = 5;
private Thread t;
private String name;
public ThreadMethod(String name) { this.name = name; }
public void runTask() {
if(t == null) {
t = new Thread(name) {
public void run() {
try {
while(true) {
System.out.println(this);
if(--countDown == 0) return;
sleep(10);
}
} catch(InterruptedException e) {
System.out.println("sleep() interrupted");
}
}
public String toString() {
return getName() + ": " + countDown;
}
};
t.start();
}
}
}
class ThreadMethod {
private int countDown = 5;
private Thread t;
private String name;
public ThreadMethod(String name) { this.name = name; }
public void runTask() {
if(t == null) {
t = new Thread(name) {
public void run() {
try {
while(true) {
System.out.println(this);
if(--countDown == 0) return;
sleep(10);
}
} catch(InterruptedException e) {
System.out.println("sleep() interrupted");
}
}
public String toString() {
return getName() + ": " + countDown;
}
};
t.start();
}
}
}
9.3至9.7中的5个例子可以通过如下的方式运行:
public class ThreadVariations {
public static void main(String[] args) {
new InnerThread1("InnerThread1");
new InnerThread2("InnerThread2");
new InnerRunnable1("InnerRunnable1");
new InnerRunnable2("InnerRunnable2");
new ThreadMethod("ThreadMethod").runTask();
public class ThreadVariations {
public static void main(String[] args) {
new InnerThread1("InnerThread1");
new InnerThread2("InnerThread2");
new InnerRunnable1("InnerRunnable1");
new InnerRunnable2("InnerRunnable2");
new ThreadMethod("ThreadMethod").runTask();
}
}
public class ThreadVariations {
public static void main(String[] args) {
new InnerThread1("InnerThread1");
new InnerThread2("InnerThread2");
new InnerRunnable1("InnerRunnable1");
new InnerRunnable2("InnerRunnable2");
new ThreadMethod("ThreadMethod").runTask();
}
}
10. Joining a Thread
在A线程中调用B线程的join()
方法,A线程会被挂起,直到B线程完成后(isAlive()
是false
),A线程才会继续运行。可以在调用join()
时加上一个表示超时的参数,如果B线程没有在时限内完成,join()
就会直接返回,使A线程得以继续运行。interrupt()
也可以打断join()
。
class Sleeper extends Thread {
public Sleeper(String name, int sleepTime) {
} catch(InterruptedException e) {
System.out.println(getName() + " was interrupted. " +
"isInterrupted(): " + isInterrupted());
System.out.println(getName() + " has awakened");
class Joiner extends Thread {
public Joiner(String name, Sleeper sleeper) {
} catch(InterruptedException e) {
System.out.println("Interrupted");
System.out.println(getName() + " join completed");
public static void main(String[] args) {
Sleeper sleepy = new Sleeper("Sleepy", 1500),
grumpy = new Sleeper("Grumpy", 1500);
Joiner dopey = new Joiner("Dopey", sleepy),
doc = new Joiner("Doc", grumpy);
Grumpy was interrupted. isInterrupted(): false
class Sleeper extends Thread {
private int duration;
public Sleeper(String name, int sleepTime) {
super(name);
duration = sleepTime;
start();
}
public void run() {
try {
sleep(duration);
} catch(InterruptedException e) {
System.out.println(getName() + " was interrupted. " +
"isInterrupted(): " + isInterrupted());
return;
}
System.out.println(getName() + " has awakened");
}
}
class Joiner extends Thread {
private Sleeper sleeper;
public Joiner(String name, Sleeper sleeper) {
super(name);
this.sleeper = sleeper;
start();
}
public void run() {
try {
sleeper.join();
} catch(InterruptedException e) {
System.out.println("Interrupted");
}
System.out.println(getName() + " join completed");
}
}
public class Joining {
public static void main(String[] args) {
Sleeper sleepy = new Sleeper("Sleepy", 1500),
grumpy = new Sleeper("Grumpy", 1500);
Joiner dopey = new Joiner("Dopey", sleepy),
doc = new Joiner("Doc", grumpy);
grumpy.interrupt();
}
}
/* Output
Grumpy was interrupted. isInterrupted(): false
Doc join completed
Sleepy has awakened
Dopey join completed
*/
class Sleeper extends Thread {
private int duration;
public Sleeper(String name, int sleepTime) {
super(name);
duration = sleepTime;
start();
}
public void run() {
try {
sleep(duration);
} catch(InterruptedException e) {
System.out.println(getName() + " was interrupted. " +
"isInterrupted(): " + isInterrupted());
return;
}
System.out.println(getName() + " has awakened");
}
}
class Joiner extends Thread {
private Sleeper sleeper;
public Joiner(String name, Sleeper sleeper) {
super(name);
this.sleeper = sleeper;
start();
}
public void run() {
try {
sleeper.join();
} catch(InterruptedException e) {
System.out.println("Interrupted");
}
System.out.println(getName() + " join completed");
}
}
public class Joining {
public static void main(String[] args) {
Sleeper sleepy = new Sleeper("Sleepy", 1500),
grumpy = new Sleeper("Grumpy", 1500);
Joiner dopey = new Joiner("Dopey", sleepy),
doc = new Joiner("Doc", grumpy);
grumpy.interrupt();
}
}
/* Output
Grumpy was interrupted. isInterrupted(): false
Doc join completed
Sleepy has awakened
Dopey join completed
*/
Sleeper
的sleep()
可以被interrupt()
打断。interrupt()
会设置一个标志位,指示线程被打断,interrupt()
产生的异常被捕获后,这个标志位就会被清除。从打印可以看到,Sleeper
捕获InterruptedException
后,查询isInterrupted()
的值为false
。之后很快就会出现打印:
Doc join completed
因为doc
对应的grumpy
已经被打断。
如果不打断grumpy
,而是打断doc
,则可以看到doc
能够被成功打断并立即完成:
public static void main(String[] args) {
Sleeper sleepy = new Sleeper("Sleepy", 1500),
grumpy = new Sleeper("Grumpy", 1500);
Joiner dopey = new Joiner("Dopey", sleepy),
doc = new Joiner("Doc", grumpy);
public class Joining {
public static void main(String[] args) {
Sleeper sleepy = new Sleeper("Sleepy", 1500),
grumpy = new Sleeper("Grumpy", 1500);
Joiner dopey = new Joiner("Dopey", sleepy),
doc = new Joiner("Doc", grumpy);
doc.interrupt();
}
}
/*
Interrupted
Doc join completed
Grumpy has awakened
Sleepy has awakened
Dopey join completed
*/
public class Joining {
public static void main(String[] args) {
Sleeper sleepy = new Sleeper("Sleepy", 1500),
grumpy = new Sleeper("Grumpy", 1500);
Joiner dopey = new Joiner("Dopey", sleepy),
doc = new Joiner("Doc", grumpy);
doc.interrupt();
}
}
/*
Interrupted
Doc join completed
Grumpy has awakened
Sleepy has awakened
Dopey join completed
*/
11. Creating Responsive User Interfaces
多线程的一个重要应用是用来创建响应式的用户界面,通过把耗时的业务放置到单独的线程去运行,前台界面就可以及时地响应用户的交互。
private volatile double d = 1;
public UnresponsiveUI() throws Exception {
d = d + (Math.PI + Math.E) / d;
System.in.read(); // Never gets here
public class ResponsiveUI extends Thread {
private static volatile double d = 1;
d = d + (Math.PI + Math.E) / d;
public static void main(String[] args) throws Exception {
//! new UnresponsiveUI(); // Must kill this process
System.out.println(d); // Shows progress
class UnresponsiveUI {
private volatile double d = 1;
public UnresponsiveUI() throws Exception {
while(d > 0)
d = d + (Math.PI + Math.E) / d;
System.in.read(); // Never gets here
}
}
public class ResponsiveUI extends Thread {
private static volatile double d = 1;
public ResponsiveUI() {
setDaemon(true);
start();
}
public void run() {
while(true) {
d = d + (Math.PI + Math.E) / d;
}
}
public static void main(String[] args) throws Exception {
//! new UnresponsiveUI(); // Must kill this process
new ResponsiveUI();
System.in.read();
System.out.println(d); // Shows progress
}
}
class UnresponsiveUI {
private volatile double d = 1;
public UnresponsiveUI() throws Exception {
while(d > 0)
d = d + (Math.PI + Math.E) / d;
System.in.read(); // Never gets here
}
}
public class ResponsiveUI extends Thread {
private static volatile double d = 1;
public ResponsiveUI() {
setDaemon(true);
start();
}
public void run() {
while(true) {
d = d + (Math.PI + Math.E) / d;
}
}
public static void main(String[] args) throws Exception {
//! new UnresponsiveUI(); // Must kill this process
new ResponsiveUI();
System.in.read();
System.out.println(d); // Shows progress
}
}
12. Thread Groups
线程组持有线程的集合,这里直接引用Thinking in Java的原话:
The value of thread groups can be summed up by a quote from Joshua Bloch, the software architect who, while he was at Sun, fixed and greatly improved the Java collections library in JDK 1.2 (among other contributions):
“Thread groups are best viewed as an unsuccessful experiment, and you may simply
ignore their existence.”
13. Catching Exceptions
异常不会跨线程传递,如果有未被处理的异常从run()
中逃了出来,该异常会被传递到控制台。在Java SE 5之前需要使用线程组来捕获异常,而在Java SE 5中则可以使用Executors
,不必直接接触线程组。
下面的代码在run()
中抛出异常:
import java.util.concurrent.*;
public class ExceptionThread implements Runnable {
throw new RuntimeException();
public static void main(String[] args) {
ExecutorService exec = Executors.newCachedThreadPool();
exec.execute(new ExceptionThread());
import java.util.concurrent.*;
public class ExceptionThread implements Runnable {
public void run() {
throw new RuntimeException();
}
public static void main(String[] args) {
ExecutorService exec = Executors.newCachedThreadPool();
exec.execute(new ExceptionThread());
}
}
import java.util.concurrent.*;
public class ExceptionThread implements Runnable {
public void run() {
throw new RuntimeException();
}
public static void main(String[] args) {
ExecutorService exec = Executors.newCachedThreadPool();
exec.execute(new ExceptionThread());
}
}
该异常未被处理,会在控制台打印出来:
Exception in thread "pool-1-thread-1" java.lang.RuntimeException
Exception in thread "pool-1-thread-1" java.lang.RuntimeException
Exception in thread "pool-1-thread-1" java.lang.RuntimeException
直接在main()中加上try-catch,依然无法捕获异常:
public class NaiveExceptionHandling {
public static void main(String[] args) {
ExecutorService exec = Executors.newCachedThreadPool();
exec.execute(new ExceptionThread());
} catch(RuntimeException ue) {
// This statement will NOT execute!
System.out.println("Exception has been handled!");
public class NaiveExceptionHandling {
public static void main(String[] args) {
try {
ExecutorService exec = Executors.newCachedThreadPool();
exec.execute(new ExceptionThread());
} catch(RuntimeException ue) {
// This statement will NOT execute!
System.out.println("Exception has been handled!");
}
}
}
public class NaiveExceptionHandling {
public static void main(String[] args) {
try {
ExecutorService exec = Executors.newCachedThreadPool();
exec.execute(new ExceptionThread());
} catch(RuntimeException ue) {
// This statement will NOT execute!
System.out.println("Exception has been handled!");
}
}
}
同样的异常仍旧会在控制台上打印出来:
Exception in thread "pool-1-thread-1" java.lang.RuntimeException
Exception in thread "pool-1-thread-1" java.lang.RuntimeException
Exception in thread "pool-1-thread-1" java.lang.RuntimeException
为了解决这个问题,需要改变Executor
产生线程的方式。Java SE 5中新加入的Thread.UncaughtExceptionHandler
接口允许为Thread
对象添加异常处理程序。当线程中出现未捕获的异常、即将终止时,Thread.UncaughtExceptionHandler.uncaughtException()
会被自动调用。
这里使用自定义ThreadFactory
的方式,为其生成的线程附加上Thread.UncaughtExceptionHandler
,然后把ThreadFactory
传递给Executors
,得到ExecutorService
。
import java.util.concurrent.*;
class ExceptionThread2 implements Runnable {
Thread t = Thread.currentThread();
System.out.println("run() by " + t);
System.out.println("eh = " + t.getUncaughtExceptionHandler());
throw new RuntimeException();
class MyUncaughtExceptionHandler implements
Thread.UncaughtExceptionHandler {
public void uncaughtException(Thread t, Throwable e) {
System.out.println("caught " + e);
class HandlerThreadFactory implements ThreadFactory {
public Thread newThread(Runnable r) {
System.out.println(this + " creating new Thread");
Thread t = new Thread(r);
System.out.println("created " + t);
t.setUncaughtExceptionHandler(new MyUncaughtExceptionHandler());
System.out.println("eh = " + t.getUncaughtExceptionHandler());
public class CaptureUncaughtException {
public static void main(String[] args) {
ExecutorService exec = Executors.newCachedThreadPool(
new HandlerThreadFactory());
exec.execute(new ExceptionThread2());
com.company.exceptions.HandlerThreadFactory@7f31245a creating new Thread
created Thread[Thread-0,5,main]
eh = com.company.exceptions.MyUncaughtExceptionHandler@6d6f6e28
run() by Thread[Thread-0,5,main]
eh = com.company.exceptions.MyUncaughtExceptionHandler@6d6f6e28
com.company.exceptions.HandlerThreadFactory@7f31245a creating new Thread
created Thread[Thread-1,5,main]
eh = com.company.exceptions.MyUncaughtExceptionHandler@c6f6863
caught java.lang.RuntimeException
import java.util.concurrent.*;
class ExceptionThread2 implements Runnable {
public void run() {
Thread t = Thread.currentThread();
System.out.println("run() by " + t);
System.out.println("eh = " + t.getUncaughtExceptionHandler());
throw new RuntimeException();
}
}
class MyUncaughtExceptionHandler implements
Thread.UncaughtExceptionHandler {
public void uncaughtException(Thread t, Throwable e) {
System.out.println("caught " + e);
}
}
class HandlerThreadFactory implements ThreadFactory {
public Thread newThread(Runnable r) {
System.out.println(this + " creating new Thread");
Thread t = new Thread(r);
System.out.println("created " + t);
t.setUncaughtExceptionHandler(new MyUncaughtExceptionHandler());
System.out.println("eh = " + t.getUncaughtExceptionHandler());
return t;
}
}
public class CaptureUncaughtException {
public static void main(String[] args) {
ExecutorService exec = Executors.newCachedThreadPool(
new HandlerThreadFactory());
exec.execute(new ExceptionThread2());
}
}
/* Output
com.company.exceptions.HandlerThreadFactory@7f31245a creating new Thread
created Thread[Thread-0,5,main]
eh = com.company.exceptions.MyUncaughtExceptionHandler@6d6f6e28
run() by Thread[Thread-0,5,main]
eh = com.company.exceptions.MyUncaughtExceptionHandler@6d6f6e28
com.company.exceptions.HandlerThreadFactory@7f31245a creating new Thread
created Thread[Thread-1,5,main]
eh = com.company.exceptions.MyUncaughtExceptionHandler@c6f6863
caught java.lang.RuntimeException
*/
import java.util.concurrent.*;
class ExceptionThread2 implements Runnable {
public void run() {
Thread t = Thread.currentThread();
System.out.println("run() by " + t);
System.out.println("eh = " + t.getUncaughtExceptionHandler());
throw new RuntimeException();
}
}
class MyUncaughtExceptionHandler implements
Thread.UncaughtExceptionHandler {
public void uncaughtException(Thread t, Throwable e) {
System.out.println("caught " + e);
}
}
class HandlerThreadFactory implements ThreadFactory {
public Thread newThread(Runnable r) {
System.out.println(this + " creating new Thread");
Thread t = new Thread(r);
System.out.println("created " + t);
t.setUncaughtExceptionHandler(new MyUncaughtExceptionHandler());
System.out.println("eh = " + t.getUncaughtExceptionHandler());
return t;
}
}
public class CaptureUncaughtException {
public static void main(String[] args) {
ExecutorService exec = Executors.newCachedThreadPool(
new HandlerThreadFactory());
exec.execute(new ExceptionThread2());
}
}
/* Output
com.company.exceptions.HandlerThreadFactory@7f31245a creating new Thread
created Thread[Thread-0,5,main]
eh = com.company.exceptions.MyUncaughtExceptionHandler@6d6f6e28
run() by Thread[Thread-0,5,main]
eh = com.company.exceptions.MyUncaughtExceptionHandler@6d6f6e28
com.company.exceptions.HandlerThreadFactory@7f31245a creating new Thread
created Thread[Thread-1,5,main]
eh = com.company.exceptions.MyUncaughtExceptionHandler@c6f6863
caught java.lang.RuntimeException
*/
MyUncaughtExceptionHandler
实现了Thread.UncaughtExceptionHandler
,这里只是将异常打印出来。HandlerThreadFactory
通过Thread
的setUncaughtExceptionHandler()
,为Thread
加上MyUncaughtExceptionHandler
用来处理异常。从打印可见,ExceptionThread2
抛出的未捕获的异常被MyUncaughtExceptionHandler
处理了。
可以通过Thread的setDefaultUncaughtExceptionHandler()
方法为Thread添加默认的异常处理:
import java.util.concurrent.*;
public class SettingDefaultHandler {
public static void main(String[] args) {
Thread.setDefaultUncaughtExceptionHandler(
new MyUncaughtExceptionHandler());
ExecutorService exec = Executors.newCachedThreadPool();
exec.execute(new ExceptionThread());
caught java.lang.RuntimeException
import java.util.concurrent.*;
public class SettingDefaultHandler {
public static void main(String[] args) {
Thread.setDefaultUncaughtExceptionHandler(
new MyUncaughtExceptionHandler());
ExecutorService exec = Executors.newCachedThreadPool();
exec.execute(new ExceptionThread());
}
}
/* Output
caught java.lang.RuntimeException
*/
import java.util.concurrent.*;
public class SettingDefaultHandler {
public static void main(String[] args) {
Thread.setDefaultUncaughtExceptionHandler(
new MyUncaughtExceptionHandler());
ExecutorService exec = Executors.newCachedThreadPool();
exec.execute(new ExceptionThread());
}
}
/* Output
caught java.lang.RuntimeException
*/
如果没有为线程单独设置UncaughtExceptionHandler,则会应用默认的UncaughtExceptionHandler(如果有的话)。