背景
平时自己在使用的ThreadPoolExecutor的时候,提交任务用submit和execute方法用的比较随意,知道当需要获取返回结果的时候用submit。但当并不需要结果的时候submit和execute用得比较随意。在一次使用submit的时候并没有获得预期结果,但也没有异常日志输出。在进行一波调试之后,任务在线程中出现异常了,但也并未出现异常抛出的情况。
代码测试
1、先用execute 查看当出现异常的情况
public class ThreadPoolTest {
private static ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 10L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(500),
new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setName("submit-execute-test");
return thread;
}
}
);
private static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss SSS");
public static void main(String[] args) {
Random random = new Random();
for (int i = 0; i < 10; i++) {
int j = i;
executor.execute(new Runnable() {
@Override
public void run() {
try {
TimeUnit.SECONDS.sleep(2 + random.nextInt(5));
} catch (InterruptedException e) {
e.printStackTrace();
}
if (j % 2 != 0) {
throw new RuntimeException("线程错误");
}
LinkedBlockingQueue<Runnable> queue = (LinkedBlockingQueue) executor.getQueue();
System.out.println(formatter.format(LocalDateTime.now()) + "::" + Thread.currentThread().getName() + "::" +
"核心线程数 :" + executor.getCorePoolSize() +
"::最大线程数 :" + executor.getMaximumPoolSize() +
"::活动线程数 :" + executor.getActiveCount() +
"::任务完成数" + executor.getCompletedTaskCount() +
"::队列使用 :" + queue.size() + "::队列未使用 :" + queue.remainingCapacity() + "::队列总共大小 :" + (queue.size() + queue.remainingCapacity()));
}
});
}
}
}
从打印中可以看到当execute提交runable的时候异常会输出。
2、我们将execute 换成submit ,其他都不变,再次查看运行情况
可以看出除了我们在代码里面输出内容并未抛出异常。
原因
查看ThreadPoolExecutor 的submit方法,是将Runable方法进行封装,再交给Executor去execute,这个方法和ThreadPoolExecutor 的execute方法一样
public Future<?> submit(Runnable task) {
if (task == null) throw new NullPointerException();
RunnableFuture<Void> ftask = newTaskFor(task, null);
execute(ftask);
return ftask;
}
newTaskFor 方法是创建FutureTask 对象,那么具体不抛异常应该就在FutureTask的run方法了。
protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
return new FutureTask<T>(runnable, value);
}
FutureTask 的run方法,在run方法中对Throwable 异常进行捕获,错误的时候将异常设置到返回结果。执行正常结束,将返回结果set到结果中
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);
}
}
建议
根据上面的分析,如果ThreadPoolExecutor 提交任务的时候如果并不关心返回结果最好直接使用ThreadPoolExecutor.execute() 方法。
版权声明:本文为fajing_feiyue原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。