在线程的run方法运行过程中,有可能抛出异常,这时你可能想这么来做:
class UncaughtThread implements Runnable{
@Override
public void run() {
System.out.println("开始处理任务...");
//打印当前线程的私有异常处理器
System.out.println(Thread.currentThread().getUncaughtExceptionHandler());
//打印当前线程的全局异常处理器
System.out.println(Thread.currentThread().getDefaultUncaughtExceptionHandler());
//这里将抛出运行时异常,0不能为除数
System.out.println(1/0);
}
}
//演示如何处理线程之中发生的异常
public static void uncaughtException(){
Thread thread = new Thread(new UncaughtThread());
// 以下的异常捕捉代码将没有任何作用
try {
thread.start();
} catch (Exception e) {
}
}
在A线程中使用try...catch{}来捕获B线程中将抛出的异常,这是完全没有效果的,除非我们使用异常处理器,如下所示:
//演示如何处理线程之中发生的异常
public static void uncaughtException(){
Thread thread = new Thread(new UncaughtThread());
//设置专有异常处理器
thread.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
//发生异常时,将会进入该方法
public void uncaughtException(Thread t, Throwable e) {
System.out.println("专有处理器处理异常:"+e.getMessage());
}
//重写一下toString,没有什么意义,只是为了打印一下
@Override
public String toString() {return super.toString()+":专有异常处理器";}
});
//为所有线程创建全局异常处理器
Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler() {
public void uncaughtException(Thread t, Throwable e) {
System.out.println("全局处理器处理异常:"+e.getMessage());
}
@Override
public String toString() {return super.toString()+":全局异常处理器";}
});
thread.start();
}
输出****************************************************************************
开始处理任务...
com.fyrj.compoment.demo.thread2.WhatThread$2@538526aa:专有异常处理器
com.fyrj.compoment.demo.thread2.WhatThread$3@4aad8dbc:全局异常处理器
专有处理器处理异常:/ by zero
*********************************************************************************
如代码中所示,我们为线程创建了一个专有的异常处理器并且还为所有线程创建一个默认全局异常处理器 ; 如果一个线程执行中发生了异常,将会先去调用专有异常处理器,如果没有则再去调用全局异常处理器;
如果我们将设置专有异常处理器下的几行代码注释,再次运行将得到如下输出结果:
输出****************************************************************************
开始处理任务...
java.lang.ThreadGroup[name=main,maxpri=10]
com.fyrj.compoment.demo.thread2.WhatThread$2@69dfe453:全局异常处理器
全局处理器处理异常:/ by zero
*********************************************************************************
我们再来介绍一下线程的join方法;
class ThreadJOIN implements Runnable{
private int sleepSeconds;
private String desc;
Thread thread = null;
public ThreadJOIN(int sleepSeconds,String desc,Thread thread) {
this.sleepSeconds = sleepSeconds;
this.desc = desc;
this.thread = thread;
}
@Override
public void run() {
try {
if(thread!=null){
// 先注释这里,看看输出结果会是什么?
// thread.join();
}
TimeUnit.MILLISECONDS.sleep(sleepSeconds);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(desc);
}
}
//演示线程的join方法
public static void join() throws InterruptedException{
Thread t1 = new Thread(new ThreadJOIN(1000, "ThreadA OVER",null));
Thread t2 = new Thread(new ThreadJOIN(500, "ThreadB OVER",t1));
Thread t3 = new Thread(new ThreadJOIN(100, "ThreadC OVER",t2));
t1.start();
t2.start();
t3.start();
}
public static void main(String[] args) throws InterruptedException, ExecutionException {
join();
}
在join方法中,我们创建了3个线程t1,t2,t3; 观察ThreadJOIN类的run方法发现,每个线程都将休眠 sleepSeconds属性值的时间,t1线程将休眠1000毫秒,t2将休眠500,t3则是100毫秒,我们先将 thread.join那行代码注释,看看输出结果是什么;
输出****************************************************************************************
ThreadC OVER
ThreadB OVER
ThreadA OVER
********************************************************************************************
这个输出结果完全在我们的意料之中,休眠时间越短的线程越先得到执行,接下来我们将注释取消,再看看输出结果!
输出****************************************************************************************
ThreadA OVER
ThreadB OVER
ThreadC OVER
********************************************************************************************
我们看到线程的运行时机反过来了,因为我们在打印t2线程的内容前,它执行了thread.join()代码,此时thread属性的引用是t1线程,而join()的作用正是等待对方运行完毕我再运行;简单来说,在A线程中,执行B线程.join(), 意思就是,等待B线程运行完毕之后A线程再运行;