前言

使用线程池难免会用到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不会出现这种情况。

原文地址:https://www.jianshu.com/p/29610984f1dd

并发编程之submit和execute区别的更多相关文章

  1. Python核心技术与实战——十七|Python并发编程之Futures

    不论是哪一种语言,并发编程都是一项非常重要的技巧.比如我们上一章用的爬虫,就被广泛用在工业的各个领域.我们每天在各个网站.App上获取的新闻信息,很大一部分都是通过并发编程版本的爬虫获得的. 正确并合 ...

  2. 并发编程之 Exchanger 源码分析

    前言 JUC 包中除了 CountDownLatch, CyclicBarrier, Semaphore, 还有一个重要的工具,只不过相对而言使用的不多,什么呢? Exchange -- 交换器.用于 ...

  3. Python进阶:并发编程之Futures

    区分并发和并行 并发(Concurrency). 由于Python 的解释器并不是线程安全的,为了解决由此带来的 race condition 等问题,Python 便引入了全局解释器锁,也就是同一时 ...

  4. Java并发编程之CAS第三篇-CAS的缺点及解决办法

    Java并发编程之CAS第三篇-CAS的缺点 通过前两篇的文章介绍,我们知道了CAS是什么以及查看源码了解CAS原理.那么在多线程并发环境中,的缺点是什么呢?这篇文章我们就来讨论讨论 本篇是<凯 ...

  5. 并发编程之ThreadLocal

    并发编程之ThreadLocal 前言 当多线程访问共享可变数据时,涉及到线程间同步的问题,并不是所有时候,都要用到共享数据,所以就需要线程封闭出场了. 数据都被封闭在各自的线程之中,就不需要同步,这 ...

  6. 并发编程之:CountDownLatch

    大家好,我是小黑,一个在互联网苟且偷生的农民工. 先问大家一个问题,在主线程中创建多个线程,在这多个线程被启动之后,主线程需要等子线程执行完之后才能接着执行自己的代码,应该怎么实现呢? Thread. ...

  7. [转载]并发编程之Operation Queue和GCD

    并发编程之Operation Queue http://www.cocoachina.com/applenews/devnews/2013/1210/7506.html 随着移动设备的更新换代,移动设 ...

  8. Java并发编程之CAS

    CAS(Compare and swap)比较和替换是设计并发算法时用到的一种技术.简单来说,比较和替换是使用一个期望值和一个变量的当前值进行比较,如果当前变量的值与我们期望的值相等,就使用一个新值替 ...

  9. 并发编程之wait()、notify()

    前面的并发编程之volatile中我们用程序模拟了一个场景:在main方法中开启两个线程,其中一个线程t1往list里循环添加元素,另一个线程t2监听list中的size,当size等于5时,t2线程 ...

随机推荐

  1. MyEclipse6.5安装SVN插件方法

    MyEclipse6.5安装SVN插件,掌握了几种方法,本节就像大家介绍一下MyEclipse6.5安装SVN插件的三种方法,看完本文你肯定有不少收获,希望本文能教会你更多东西. 一.安装方法: My ...

  2. springboot拦截器之验证登录

    添加jar包,这个jar包不是必须的,只是在拦截器里用到了,如果不用的话,完全可以不引入 <dependency> <groupId>org.apache.commons< ...

  3. Leetcode103. Binary Tree Zigzag Level Order Traversal二叉树的锯齿形层次遍历

    给定一个二叉树,返回其节点值的锯齿形层次遍历.(即先从左往右,再从右往左进行下一层遍历,以此类推,层与层之间交替进行). 例如: 给定二叉树 [3,9,20,null,null,15,7], 3 / ...

  4. 1858: [Scoi2010]序列操作

    1858: [Scoi2010]序列操作 Time Limit: 10 Sec Memory Limit: 64 MB Submit: 3397 Solved: 1624 [Submit][Statu ...

  5. loj2544 「JXOI2018」游戏

    https://loj.ac/problem/2544 自己太傻,一遇到有关数学的题就懵逼,这种简单题竟然还得靠NicoDafaGood 在$[l,r]$这个区间内,如果没有数是$x$的因数,我们称$ ...

  6. js图片碎片效果(移动端也适用)

    <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content ...

  7. 20190813「Night」-Blind

    夜场. 先说说题面,周,任,飞? 好像是个巨巨巨巨巨巨佬. 郭神?同上. 好像题解包里都有. %%%出题人liu_runda. liu_runda是谁? 凭实力在NOI2017退役的辣鸡蒟蒻. 郭神是 ...

  8. 【C++】从最简单的vector中sort用法到自定义比较函数comp后对结构体排序的sort算法

    sort函数在使用中非常好用,也非常简单,而且效率与冒泡或者选择排序不是一个数量级.本文就sort函数在vector中的用法分为sort函数入门用法与自定义comp比较函数比较结构体这两个最基本的功能 ...

  9. A Simple Problem with Integers POJ - 3468 (线段树)

    思路:线段树,区间更新,区间查找 #include<iostream> #include<vector> #include<string> #include< ...

  10. plsql中学习job

    --1.plsql中学习job --学习job --建表 create table test_job(para_date date); commit; insert into test_job val ...