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 interrupts
int 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、因此,被问到线程池异常处理,如何回答?