#(单线程情况)

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

/**         
                    * Author: scw         
                    * Time: 16-11-24         
                    */         
          public           class           RewriteUncatchtExceptionHandler           implements           Thread.UncaughtExceptionHandler{         
                    public           void           uncaughtException(Thread t, Throwable e) {         
                    System.out.println(          "我捕获到了线程池的异常"          );         
                    }         
          }

/**         
                    * Author: scw         
                    * Time: 16-11-24         
                    */         
          public           class           Task           implements           Runnable {         
                    public           void           run() {         
                    System.out.println(          "执行任务"          );         
                    int           num  = Integer.parseInt(          "TT"          );         
                    }         
          }

/**         
                    * 对于单个线程出现的异常情况可以使用异常处理器,可以捕获到         
                    */         
                    public           static           void           catchSingleThread() {         
                    Task task =           new           Task();         
                    Thread thread =           new           Thread(task);         
                    thread.setUncaughtExceptionHandler(          new           RewriteUncatchtExceptionHandler());         
               thread.start();         
           }


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

#(线程池)

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

/**         
                    * 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,使线程池内线程皆为守护线程,主线程退出后,强制销毁线程池

/**         
                    * 虽然从写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的时候是不成功的,那么我们应该如何选择呢?

/**         
                    * 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其实是无效的



此外, 这篇文章详细了剖析了源码,解释了为什么submit时,异常被吃掉了

以下是那篇文章的结论:


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