2020-7-8 线程池中execute()⽅法和submit()⽅法的区别?_execute0方法只能执行runnable类型的任务,submit0方法可以执行runnable和-程序员宅基地

技术标签: 多线程  并发编程  

最简单的回答

	1、execute()只能执行Runnable任务,submit()能执行Callable和Runnable任务;
	2、submit()可获取任务执行结果,execute()不行

原理

看波继承关系

线程池类图

submit()源码

submit()在AbstractExecutorService中有实现,实现过程如下:

public Future<?> submit(Runnable task) {
    if (task == null) throw new NullPointerException();
     //  封装成FutureTask
     RunnableFuture<Void> ftask = newTaskFor(task, null);
     execute(ftask);
     return ftask;
 }

public <T> Future<T> submit(Runnable task, T result) {
    if (task == null) throw new NullPointerException();
    RunnableFuture<T> ftask = newTaskFor(task, result);
    execute(ftask);
    return ftask;
}

public <T> Future<T> submit(Callable<T> task) {
    if (task == null) throw new NullPointerException();
    RunnableFuture<T> ftask = newTaskFor(task);
    execute(ftask);
    return ftask;
}

由上可知submit()一共有三个重载方法,可执行Callable/Runnable任务,验证回答的第一点,且他们的执行过程几乎一样,步骤如下:
1、判断任务是否为空,为空则抛出异常
2、将任务封装成FutureTask对象
3、调用execute()执行任务
4、返回FutureTask

如何封装成FutureTask对象
protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
    return new FutureTask<T>(callable);
}

execute()源码

public void execute(Runnable command) {
	xxx...
	addWorker(command, true)
}

由上可知,execute()方法只能执行Runnable任务,且FutureTask继承了Runnable接口,因此submit()最终交给execute()执行没问题,而在该方法中,其余可以先不看,就看addWorker(command, true),意思为创建一个线程来执行该任务,command指任务,true是指用核心线程执行;而在addWorker()方法中,其他我们也不看,只看他最终会调用工作线程执行该任务,代码如下

private boolean addWorker(Runnable firstTask, boolean core) {
	xxx...
	//	开始执行任务
	t.start();
}

为什么submit()方法可以有返回结果,就是因为FutureTask

FutureTask是个Runnable任务,在执行任务时会调用其的run()方法,如下:

public void run() {
    xxx...
    try {
        //  获取任务
        Callable<V> c = callable;
        if (c != null && state == NEW) {
            V result;
            boolean ran;
            try {
                //  执行任务
                result = c.call();
                ran = true;
            } catch (Throwable ex) {
                xxx...
            }
            //  如果执行成功,会设置执行结果
            if (ran)
                set(result);
        }
    } finally {
        xxx...
    }
}

上述代码中,略去其他操作,只管这里面他会执行任务,并且执行任务成功后,会设置任务执行结果

set(result)
protected void set(V v) {
	//	通过unsafe对象来CAS设置FutureTask的执行状态
    if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
    	//	设置执行结果
        outcome = v;
        //	其他...
        UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state
        finishCompletion();
    }
}

上述代码可知,set()方法中主要做的就是通过unsafe对象来CAS设置FutureTask的执行状态,设置成功后(即任务执行完),就设置执行结果,outcome实际上是FutureTask的一个属性,表示执行结果

/** The result to return or exception to throw from get() */
private Object outcome; // non-volatile, protected by state reads/writes

小结

1、submit()能执行多种任务是由于AbstractExecutorService提供了几种不同的重载方法,支持Callable和Runnable;
   execute()只能执行Runnable是由于ThreadPoolExecutor只提供了执行Runnable任务的方法;
2、源码方面:
   1)submit()实际是将任务封装成FutureTask对象,最终还是调用的execute(),不过会返回这个Future对象;
      而FutureTask继承Runnable,在执行该任务时会调用其中的run()方法;
      并且该类中有个叫outcome的属性,会用来存储执行的结果;
      在执行run()方法时,如果任务成功执行,那么就会调用set()方法来设置outcome;
      因此,我们获取的Future对象在调用get()方法时,就能获取到任务的执行结果
   2)execute()主要负责根据条件创建worker来执行任务,他的执行过程就是线程池的执行流程(这里不做拓展了)
如果被问到,最开始那两点应该时随便回答的,后面源码方面的可以扩展,当然自己要熟悉,最好看过一遍,
我也是最近看了《并发编程之美》学了点,深层次的还搞不透,不过这点扯一波还是感觉有点点东西的。
																									 2020-7-8
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_42130098/article/details/107212655

智能推荐

java开发Demo~微信扫码支付,java开发示例-程序员宅基地

文章浏览阅读550次。开发所需工具类开发所需jar具体的代码不贴了,说明下PayConfigUtil中的参数APP_ID和APP_SECRET在公众平台MCH_ID和API_KEY在商户平台,其中API_KEY是自己设置的,并不是自动生成的。Controlle..._微信支付对应示例 java appid secret

【Latex使用algorithm2e包生成伪代码 实现取消自动编号及添加子编号方法】_tex algorithm标号-程序员宅基地

文章浏览阅读538次,点赞15次,收藏3次。algorithm2e包实现子编号问题_tex algorithm标号

字典序问题_在数据加密和数据压缩中常需要对特殊的字符串进行编码。给定的字母表 a 由 26 个-程序员宅基地

文章浏览阅读1.6w次,点赞11次,收藏39次。在数据加密和数据压缩中常需要对特殊的字符串进行编码。给定的字母表A由26个小写字母组成。该字母表产生的升序字符串中字母从左到右出现的次序与字母在字母表中出现的次序相同,且每个字符最多出现1次。例如,a,b,ab,bc,xyz等字符串都是升序字符串。现在对字母表中产生的所有长度不超过6的升序字符串,计算它在字典中的编码。123…ab_在数据加密和数据压缩中常需要对特殊的字符串进行编码。给定的字母表 a 由 26 个

Spring Security 认证与授权流程_spring security认证和授权流程-程序员宅基地

文章浏览阅读6.6k次,点赞6次,收藏20次。Spring Security 认证与授权流程_spring security认证和授权流程

Flutter 2进阶(八):EventBus、轮播图与沉浸式状态栏_flutter_statusbar_manager-程序员宅基地

文章浏览阅读2.2k次。开发中,必须要用到的也就这三个小插件了。这里主要讲一下 EventBus,轮播图和沉浸式状态栏教程很多并且很简单。下面主要用上面三个实现的功能,b站广告图,沉浸式状态栏,以及点击左上角头像用 eventbus 进入我的页面,效果图如下:下载链接,建议去 CSDN 下载,不要积分,CSDN 是阶段性代码,GitHub 有时忘记传上去:CSDN :flutter_blbl.zip-Android文档类资源-CSDN下载GitHub:https://github.com/wuqingse._flutter_statusbar_manager

ARP实现简单断网攻击_arp断网攻击演示-程序员宅基地

文章浏览阅读2.6k次。ARP实现简单断网攻击环境准备:1:一台kali2:一台win7虚拟机在讲如何进行攻击前,我先来简单介绍下arp(已经有很多大佬的博客把原理写的很清楚了,大家如有需要可以自己详细去看下,这里附上大佬博客:arp攻击arp:地址解析协议,目的是实现IP地址与MAC地址的转换,而MAC地址是真正计算机唯一标识arp攻击则是利用这一特点来进行攻击的,假设B向A发送数据,C就伪造成A,这就造成了劫持数据,造成断网,甚至监听原理大概就是这样了,我就细细讲下攻击过程(原理主要是自己也不太会写,写出来全是口_arp断网攻击演示

随便推点

高效率OCR场景文字图片合成工具发布!_可控ocr图像生成-程序员宅基地

文章浏览阅读7.2k次,点赞61次,收藏12次。OCR,光学字符识别(OPTICAL CHARACTER RECOGNITION),作为计算机视觉领域的经典问题之一它指对图像中的文字进行检测识别(包括文字检测+文字识别),并获取文本的结果。常见于拍照检查、文档识别、证照票据识别、车牌识别、自然场景下的文本定位识别等,相关技术在数字时代得到了广泛的应用。如下图是OCR识别结果:作为计算机视觉领域的OCR识别在训练的时候当然也会需要大量的图片数据来供神经网络的学习,一般需要数以千万计的图片才能训练一个文字识别系统,才能达到识别文字的目的。但是如果采用_可控ocr图像生成

使用A*算法求解迷宫问题-程序员宅基地

文章浏览阅读90次。本题目要求读入一个5*5的迷宫,然后输出基于A*算法求解的从左上角(0,0)到右下角(4,4)的路径。

如何使用字符流读写文件(非文本)?_ivfilxv-程序员宅基地

文章浏览阅读1.9k次,点赞4次,收藏2次。使用字符流读取文件(非文本)上篇博客 为什么不能使用字符流读取非文本的二进制文件? 分析了为什么无法使用字符流读取文件的原因,是因为编码方式的问题(二进制数据是无编码的)。以Java的字符流读取文件为例:它只能读取0-65535之间的字符,可以看出来字符都是正数,但是二进制的byte是可以为负数的。但是读取的时候会被当做正数来读取,或者是无法在编码表中找到的字符会返回一个奇怪的符号(你可能见过那..._ivfilxv

visual studio 中的 resharper C++ 插件快速入门指南-程序员宅基地

文章浏览阅读3.9k次,点赞9次,收藏27次。visual studio已经是极具效率的C++生产工具,但是这还不够。使用Resharper C++插件,可以更多的帮助到你。愉快转向现代C++,轻松了解C++中最棘手的方面。快速识别不会发现的错误和代码效率低下,通过安全的快速修复和强大的重构来消除它们。这些都可以通过Resharper来实现。_resharper c++

软件测试之【单元测试、系统测试、集成测试】-程序员宅基地

文章浏览阅读2.3k次,点赞11次,收藏10次。也称为混合式集成,集合了自顶向下和自底向上两种策略的优点,它将系统划分为3层,中间一层为目标层,测试的时候,对目标层上面的一层使用自顶向下的集成策略,对目标层下面的一层使用自底向上的集成策略,最后测试在目标层会合。考虑了项目的进度压力,兼顾进度和质量,在两者之间寻找均衡点进行测试,该集成的最基本策略是把最早可获得的代码拿来立即进行集成,必要的时候开发桩模块和驱动模块,在最大程度上保持与开发的并行性,从而缩短了项目集成的时间。系统测试的对象:软硬件集合在一起的系统,集成后的产品,不应是独立的软件与硬件环境。

华为软件笔试_软件 笔试-程序员宅基地

文章浏览阅读1.8k次。1.n=int(input())mn=[]for i in range(n): aa=[] for j in range(2): line=int(input()) aa.append(line) mn.append(aa)def Last(n, m): if not n or not m: ..._软件 笔试

推荐文章

热门文章

相关标签