线程的异常捕获与线程池的异常捕获 execute与submit区别

https://www.cnblogs.com/wscit/p/6100476.html


#(单线程情况)

对于单线程来说,只需要重写UncaughtException就好了,如下:

1
2
3
4
5
6
7
8
9
/**
  * Author: scw
  * Time: 16-11-24
  */
public  class  RewriteUncatchtExceptionHandler  implements  Thread.UncaughtExceptionHandler{
     public  void  uncaughtException(Thread t, Throwable e) {
         System.out.println( "我捕获到了线程池的异常" );
     }
}
1
2
3
4
5
6
7
8
9
10
/**
  * Author: scw
  * Time: 16-11-24
  */
public  class  Task  implements  Runnable {
     public  void  run() {
         System.out.println( "执行任务" );
         int  num  = Integer.parseInt( "TT" );
     }
}
1
2
3
4
5
6
7
/**
      * 对于单个线程出现的异常情况可以使用异常处理器,可以捕获到
      */
     public  static  void  catchSingleThread() {
         Task task =  new  Task();
         Thread thread =  new  Thread(task);
         thread.setUncaughtExceptionHandler( new  RewriteUncatchtExceptionHandler());
     thread.start();
 }

  运行程序,我们发现可以正常的捕获到这个unchecked异常,但是线程池中我们应该怎么处理呢?如下:

#(线程池)

首先我们要重写 ThreadFactory来为每个线程实例化的时候创建一个handler

1
2
3
4
5
6
7
8
9
10
11
12
/**
  * Author: scw
  * Time: 16-11-24
  */
public  class  MyThreadFactory  implements  ThreadFactory{
     public  Thread newThread(Runnable r) {
         Thread t =  new  Thread(r);
         t.setUncaughtExceptionHandler( new  RewriteUncatchtExceptionHandler());
         System.out.println( "Thread["  + t.getName() +  "] created." );
         return  t;
     }
}

  这个地方还可以setDemon,使线程池内线程皆为守护线程,主线程退出后,强制销毁线程池

1
2
3
4
5
6
7
8
/**
    * 虽然从写ThreadFactory以后,可以捕获到异常,但是只能是execute,而submit还是不行  how to choose one
    */
   public  static  void  catchedExecutor() {
       ExecutorService executorService = Executors.newCachedThreadPool( new  MyThreadFactory());
       executorService.execute( new  Task());
       executorService.shutdownNow();
   }

  现在问题来了,就是这样虽然可以捕获到异常,但是只能是使用execute的时候可以,使用submit的时候是不成功的,那么我们应该如何选择呢?

1
2
3
4
5
6
7
8
9
10
/**
  * how to choose submit() or execute()
  * There is a difference concerning exception/error handling.A task queued with execute() that generates some Throwable will cause the UncaughtExceptionHandler
  * for the Thread running the task to be invoked. The default UncaughtExceptionHandler, which typically prints the Throwable stack trace to System.err, will be
  * invoked if no custom handler has been installed.On the other hand, a Throwable generated by a task queued with submit() will bind the Throwable to the Future
  * that was produced from the call to submit(). Calling get() on that Future will throw an ExecutionException with the original Throwable as its cause (accessible
  * by calling getCause() on the ExecutionException).
  * Author: scw
  * Time: 16-11-24
  */

  意思就是说二者最大的区别就是异常处理上,

在execute的时候,如果你没有实现一个handler,那么他就使用默认的handler来处理异常,你要是实现了一个handler他就会使用的实例化的handler

除此之外,也可以改写ThreadPoolExecutor.afterExecute()中自定义异常

但是对于submit来说,异常是绑定到Future上了,但是调用future.get()的时候,这些异常才会给你抛出来,意味着你自己定义的handler其实是无效的



此外,https://segmentfault.com/a/1190000000669942 这篇文章详细了剖析了源码,解释了为什么submit时,异常被吃掉了

以下是那篇文章的结论:

如果我们关心线程池执行的结果,则需要使用submit来提交task,那么在afterExecute中对异常的处理也需要通过Future接口调用get方法去取结果,才能拿到异常,如果我们不关心这个任务的结果,可以直接使用ExecutorService中的execute方法(实际是继承Executor接口)来直接去执行任务,这样的话,我们的Runnable没有经过多余的封装,在runWorker中得到的异常也直接能在afterExecute中捕捉。好了,以上就是对线程池异常捕捉的一个记录。想想应该不难,今天也是偶然机会看到的。今天在开发中碰到PHP锁的问题,头疼死了。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值