并发编程之submit和execute区别
Posted jpfss
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了并发编程之submit和execute区别相关的知识,希望对你有一定的参考价值。
前言
使用线程池难免会用到submit和execute,但是submit是有坑的,此处做个记录
1、submit坑
此处随便写一个方法,进入内部查看execute和submit
/**
* @Author: 小混蛋
* @CreateDate: 2018/8/29 9:58
*/
@Component
public class Test
public static void main(String[] args)
ExecutorService es = Executors.newFixedThreadPool(5);
ArrayList<Future<?>> arrayList = new ArrayList();
for (int i = 0; i < 10; i++)
final int b = i;
Future<?> submit = es.submit(() ->
System.out.println(Thread.currentThread().getName());
int a = b / 0;
);
arrayList.add(submit);
arrayList.forEach(s ->
try
s.get();
catch (InterruptedException |ExecutionException e)
e.printStackTrace();
);
es.shutdown();
@Scheduled(cron = "")
public void test()
ctrl加鼠标左键进入submit,查看AbstractExecutorService,发现submit底层调用的还是execute,但是提交的任务不是task,而是在task的基础上封装了一层FutureTask
public Future<?> submit(Runnable task)
if (task == null) throw new NullPointerException();
RunnableFuture<Void> ftask = newTaskFor(task, null);
execute(ftask);
return ftask;
重点来了,当submit提交的task里面出现未检查异常如RuntimeException和Error等,直接execute你的task肯定是抛异常;但是使用submit之后提交的FutureTask我们看下它的源码run方法:run方法和我们直接提交的task的run方法并不一样,该方法会对所有的Throwable类型进行捕获,并把异常通过setException保存在内部变量outcome里面。所以线程池执行的过程中异常不会被抛出
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 = null;
int s = state;
if (s >= INTERRUPTING)
handlePossibleCancellationInterrupt(s);
protected void setException(Throwable t)
if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING))
outcome = t;
UNSAFE.putOrderedInt(this, stateOffset, EXCEPTIONAL); // final state
finishCompletion();
另一个重点来了,当submit被futuretask.get的时候。会在report方法调用过程中抛出这个未检查异常!
public V get() throws InterruptedException, ExecutionException
int s = state;
if (s <= COMPLETING)
s = awaitDone(false, 0L);
return report(s);
private V report(int s) throws ExecutionException
Object x = outcome;
if (s == NORMAL)
return (V)x;
if (s >= CANCELLED)
throw new CancellationException();
throw new ExecutionException((Throwable)x);
结论
1、submit在执行过程中与execute不一样,不会抛出异常而是把异常保存在成员变量中,在FutureTask.get阻塞获取的时候再把异常抛出来。
2、Spring的@Schedule注解的内部实现就是使用submit,因此,如果你构建的任务内部有未检查异常,你是永远也拿不到这个异常的。
3、execute直接抛出异常之后线程就死掉了,submit保存异常线程没有死掉,因此execute的线程池可能会出现没有意义的情况,因为线程没有得到重用。而submit不会出现这种情况。
以上是关于并发编程之submit和execute区别的主要内容,如果未能解决你的问题,请参考以下文章
并发编程之多线程基础-Thread和Runnable的区别及联系