1、当提交新任务时,异常如何处理呢?
先来看一段代码:
ExecutorService threadPool = Executors.newFixedThreadPool(5);for (int i = 0; i < 5; i++) {threadPool.submit(() -> {System.out.println("current thread name" + Thread.currentThread().getName());Object object = null;System.out.print("result## "+object.toString());});}
显然,这段代码会有异常,再来看看运行结果
虽然没有结果输出,但是也没有抛出异常,所以无法感知任务出现了异常,所以需要添加try/catch。如下图:
/*** ThreadPoolTest* <p>* encoding:UTF-8** @author Fcant 上午 09:27 2021/9/1/0001*/public class ThreadPoolTest {public static void main(String[] args) {ExecutorService threadPool = Executors.newFixedThreadPool(5);for (int i = 0; i < 5; i++) {threadPool.submit(() -> {System.out.println("current thread name" + Thread.currentThread().getName());try {Object object = null;System.out.print("result## " + object.toString());} catch (Exception e) {System.out.println("程序出异常啦!!!");}});}}}
2、线程池exec.submit()的执行流程
通过debug上面有异常的submit方法,处理有异常submit方法的主要执行流程图如下:
submit方法执行流程
//构造feature对象/*** @throws RejectedExecutionException {@inheritDoc}* @throws NullPointerException {@inheritDoc}*/public Future<?> submit(Runnable task) {if (task == null) throw new NullPointerException();RunnableFuture<Void> ftask = newTaskFor(task, null);execute(ftask);return ftask;}protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {return new FutureTask<T>(runnable, value);}public FutureTask(Runnable runnable, V result) {this.callable = Executors.callable(runnable, result);this.state = NEW; // ensure visibility of callable}public static <T> Callable<T> callable(Runnable task, T result) {if (task == null)throw new NullPointerException();return new RunnableAdapter<T>(task, result);}//线程池执行public void execute(Runnable command) {if (command == null)throw new NullPointerException();int c = ctl.get();if (workerCountOf(c) < corePoolSize) {if (addWorker(command, true))return;c = ctl.get();}if (isRunning(c) && workQueue.offer(command)) {int recheck = ctl.get();if (! isRunning(recheck) && remove(command))reject(command);else if (workerCountOf(recheck) == 0)addWorker(null, false);}else if (!addWorker(command, false))reject(command);}//捕获异常public void run() {if (state != NEW ||!UNSAFE.compareAndSwapObject(this, runnerOffset,null, Thread.currentThread()))return;try {Callable<V> c = callable;if (c != null && state == NEW) {V result;boolean ran;try {result = c.call();ran = true;} catch (Throwable ex) {result = null;ran = false;setException(ex);}if (ran)set(result);}} finally {// runner must be non-null until state is settled to// prevent concurrent calls to run()runner = null;// state must be re-read after nulling runner to prevent// leaked interruptsint s = state;if (s >= INTERRUPTING)handlePossibleCancellationInterrupt(s);}}
通过以上分析,submit执行的任务,可以通过Future对象的get方法接收抛出的异常,再进行处理。再通过一个demo,看一下Future对象的get方法处理异常的姿势,如下图:
import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.Future;/*** ThreadPoolTest* <p>* encoding:UTF-8** @author Fcant 上午 09:27 2021/9/1/0001*/public class ThreadPoolTest {public static void main(String[] args) {ExecutorService threadPool = Executors.newFixedThreadPool(5);for (int i = 0; i < 5; i++) {Future future = threadPool.submit(() -> {System.out.println("current thread name" + Thread.currentThread().getName());Object object = null;System.out.print("result## " + object.toString());});try {future.get();} catch (Exception e) {System.out.println("程序出异常啦!!!");}}}}

因此,可以使用这两种方案处理线程池异常:
- 在任务代码
try/catch捕获异常, - 通过
Future对象的get方法接收抛出的异常3、为工作者线程设置
也可以为工作者线程设置UncaughtExceptionHandler,在uncaughtException方法中处理异常UncaughtExceptionHandler,在uncaughtException方法中处理异常,直接看这样实现的正确姿势:
运行结果:ExecutorService threadPool = Executors.newFixedThreadPool(1, r -> {Thread t = new Thread(r);t.setUncaughtExceptionHandler((t1, e) -> {System.out.println(t1.getName() + "线程抛出的异常"+e);});return t;});threadPool.execute(()->{Object object = null;System.out.print("result## " + object.toString());});
4、重写
这是jdk文档的一个demo:ThreadPoolExecutor的afterExecute方法,处理传递的异常引用class ExtendedExecutor extends ThreadPoolExecutor {// 这可是jdk文档里面给的例子。。protected void afterExecute(Runnable r, Throwable t) {super.afterExecute(r, t);if (t == null && r instanceof Future<?>) {try {Object result = ((Future<?>) r).get();} catch (CancellationException ce) {t = ce;} catch (ExecutionException ee) {t = ee.getCause();} catch (InterruptedException ie) {Thread.currentThread().interrupt(); // ignore/reset}}if (t != null)System.out.println(t);}}}
5、因此,被问到线程池异常处理,如何回答?


