Java线程池中submit() 和 execute()方法有什么区别
点个关注,必回关
文章目录
- 一. execute和submit的区别与联系
- 1、测试代码的整体框架如下:
- 2、首先研究Future<?> submit(Runnable task)和void execute(Runnable command),
- 3、submit(Runnable task, T result) 方法可以使submit执行完Runnable任务后返回指定的返回值。
- 4、submit(Callable<T> task)这个方法没什么好说的,用来提交Callable类型任务,返回值由call方法决定。
- 5、关于execute和submit遭遇异常的表现
一. execute和submit的区别与联系
- execute和submit都属于线程池的方法,execute只能提交Runnable类型的任务,而submit既能提交Runnable类型任务也能提交哦啊Callable类型任务
- execute会直接抛出任务执行时的异常,submit会吃掉异常,可以通过Future的get方法将任务执行时的异常重新抛出
- execute所属顶层接口是Executor,submit所属顶层接口是ExecutorService,实现类ThreadPoolExecutor重写了execute方法,抽象类AbstractExecutorService重写了submit方法。
submit和execute由于参数不同有四种实现形式,
如下所示,本文主要研究这四种形式在各自使用场景下的区别和联系
<T> Future<T> submit(Callable<T> task);
<T> Future<T> submit(Runnable task, T result);
Future<?> submit(Runnable task);
void execute(Runnable command);
关于Runnable和Callable任务如果你还存在疑惑,建议你先看看我的另一篇文章Runnable和Callable的区别和联系。
1、测试代码的整体框架如下:
import java.util.concurrent.*;public class TestSubmitAndExecute {static ExecutorService executor = Executors.newCachedThreadPool();public static void main(String[] args) {initExecutors();/**put test codes here*//***/waitToTerminated();}private static void initExecutors() {if (executor.isTerminated()) {executor = Executors.newCachedThreadPool();}}private static void waitToTerminated() {executor.shutdown();while (!executor.isTerminated()) {}}/*** 测试 submit(Callable<T> task)** @param callable* @param <T>* @return*/public static <T> T testSubmitCallable(Callable callable) {Future<T> future = executor.submit(callable);T result = null;try {result = future.get();} catch (InterruptedException e) {e.printStackTrace();} catch (ExecutionException e) {e.printStackTrace();}return result;}/*** 测试submit(Runnable task, T result)** @param runnable* @param t* @param <T>* @return*/public static <T> T testSubmitRunnable(Runnable runnable, T t) {Future<T> future = executor.submit(runnable, t);T result = null;try {result = future.get();} catch (InterruptedException e) {e.printStackTrace();} catch (ExecutionException e) {e.printStackTrace();}return result;}/*** 测试 submit(Runnable task)* submit提交Runnable任务会默认返回null** @param runnable* @return*/public static Object testSubmitRunnable(Runnable runnable) {Future<?> future = executor.submit(runnable);Object v = null;try {v = future.get();} catch (InterruptedException e) {e.printStackTrace();} catch (ExecutionException e) {e.printStackTrace();}return v;}/*** 测试 execute(Runnable command)* execute会直接抛出异常,submit只有通过调用Future对象的get方法才能获取异常** @param runnable*/public static void testExecuteRunnable(Runnable runnable) {executor.execute(runnable);}
}
这个测试框架提供了4个静态方法用来测试submit和execute总共包含的四种表现形式,除此之外提供initExecutors用于提前检测线程池是否终止,若终止则初始化,waitToTerminated方法用于关闭线程池,并阻塞到线程池终止为止。
除了测试框架之外提供了4个不同的任务,分别测试Callable和Runnable在抛异常时的表现形式。
class CallableTask implements Callable<Integer> {@Overridepublic Integer call() throws Exception {int sum = 0;for (int i = 0; i < 520; i++) {sum += i;}return sum;}
}/*** 会抛异常的CallableTask*/
class ExceptionCallableTask implements Callable<Boolean> {public Boolean call() throws Exception {int num = 1 / 0;return false;}
}class RunnableTask implements Runnable {@Overridepublic void run() {System.out.println("I am a runnable task");}
}/*** 会抛异常的RunnableTask*/
class ExceptionRunableTask implements Runnable {@Overridepublic void run() {int num = 1 / 0;}
}
整体结构搭起来,下来就是研究具体差异的时刻了。
2、首先研究Future<?> submit(Runnable task)和void execute(Runnable command),
这两个方法都是执行Runnable类型任务,前者有返回值,但是返回值为null,后者无返回值。
public static void main(String[] args) {initExecutors();/**put test codes here*/Object object = testSubmitRunnable(new RunnableTask());System.out.println(object);testExecuteRunnable(new RunnableTask());/***/waitToTerminated();}
很容易观察控制台输出如下:
I am a runnable task
null
I am a runnable task
可以看出submit执行Runnable类型任务时默认返回值为null。如果我们需要submit在提交Runnable任务可以返回非空,就需要用到submit的另外一个重载的方法: Future submit(Runnable task, T result);
3、submit(Runnable task, T result) 方法可以使submit执行完Runnable任务后返回指定的返回值。
main方法如下:
public static void main(String[] args) {initExecutors();/**put test codes here*/
// Object object = testSubmitRunnable(new RunnableTask());
// System.out.println(object);
//
// testExecuteRunnable(new RunnableTask());Integer i = testSubmitRunnable(new RunnableTask(), 3);System.out.println(i);Boolean bool = testSubmitRunnable(new RunnableTask(), true);System.out.println(bool);String str = testSubmitRunnable(new RunnableTask(), "你好吗");System.out.println(str);/***/waitToTerminated();}
控制台输出:
I am a runnable task
3
I am a runnable task
true
I am a runnable task
你好吗
可以看出我们输入的什么参数,任务执行完毕后就返回什么参数。
4、submit(Callable task)这个方法没什么好说的,用来提交Callable类型任务,返回值由call方法决定。
main方法如下:
public static void main(String[] args) {initExecutors();/**put test codes here*/
// Object object = testSubmitRunnable(new RunnableTask());
// System.out.println(object);
//
// testExecuteRunnable(new RunnableTask());// Integer i = testSubmitRunnable(new RunnableTask(), 3);
// System.out.println(i);
//
// Boolean bool = testSubmitRunnable(new RunnableTask(), true);
// System.out.println(bool);
//
// String str = testSubmitRunnable(new RunnableTask(), "你好吗");
// System.out.println(str);Object o = testSubmitCallable(new CallableTask());System.out.println(o);/***/waitToTerminated();}
CallableTask的执行逻辑是计算0到520之间的所有整数之和,所以控制台输出:
134940
5、关于execute和submit遭遇异常的表现
execute直接将任务执行时期的异常抛出,main方法和控制台打印分别如下:
public static void main(String[] args) {initExecutors();/**put test codes here*/
// Object object = testSubmitRunnable(new RunnableTask());
// System.out.println(object);
//
// testExecuteRunnable(new RunnableTask());// Integer i = testSubmitRunnable(new RunnableTask(), 3);
// System.out.println(i);
//
// Boolean bool = testSubmitRunnable(new RunnableTask(), true);
// System.out.println(bool);
//
// String str = testSubmitRunnable(new RunnableTask(), "你好吗");
// System.out.println(str);// Object o = testSubmitCallable(new CallableTask());
// System.out.println(o);testExecuteRunnable(new ExceptionRunableTask());/***/waitToTerminated();}
Exception in thread "pool-1-thread-1" java.lang.ArithmeticException: / by zeroat ExceptionRunableTask.run(TestRunnableAndCallable.java:38)at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)at java.lang.Thread.run(Thread.java:745)
submit比较特殊,如果没有通过Future.get来获取结算结果,则吃掉异常。先将测试方法稍做调整,修改成如下形式:
/*** 测试 submit(Callable<T> task)** @param callable* @param <T>* @return*/public static <T> T testSubmitCallable(Callable callable) {Future<T> future = executor.submit(callable);T result = null;/*try {result = future.get();} catch (InterruptedException e) {e.printStackTrace();} catch (ExecutionException e) {e.printStackTrace();}*/return result;}
当我们在main方法添加如下代码时,控制台其实没有打印任何异常
public static void main(String[] args) {initExecutors();/**put test codes here*/
// Object object = testSubmitRunnable(new RunnableTask());
// System.out.println(object);
//
// testExecuteRunnable(new RunnableTask());// Integer i = testSubmitRunnable(new RunnableTask(), 3);
// System.out.println(i);
//
// Boolean bool = testSubmitRunnable(new RunnableTask(), true);
// System.out.println(bool);
//
// String str = testSubmitRunnable(new RunnableTask(), "你好吗");
// System.out.println(str);// Object o = testSubmitCallable(new CallableTask());
// System.out.println(o);// testExecuteRunnable(new ExceptionRunableTask());testSubmitCallable(new ExceptionCallableTask());/***/waitToTerminated();}
**```
如果将testSubmitCallable代码中被注释的部分取消注释,则可以看到异常信息如下:**```bash
java.util.concurrent.ExecutionException: java.lang.ArithmeticException: / by zeroat java.util.concurrent.FutureTask.report(FutureTask.java:122)at java.util.concurrent.FutureTask.get(FutureTask.java:192)at TestSubmitAndExecute.testSubmitCallable(TestSubmitAndExecute.java:58)at TestSubmitAndExecute.main(TestSubmitAndExecute.java:28)
Caused by: java.lang.ArithmeticException: / by zeroat ExceptionCallableTask.call(TestRunnableAndCallable.java:20)at ExceptionCallableTask.call(TestRunnableAndCallable.java:18)at java.util.concurrent.FutureTask.run(FutureTask.java:266)at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)at java.lang.Thread.run(Thread.java:745)
关于execute和submit的简单研究到此结束,谢谢。
相关文章:
Java线程池中submit() 和 execute()方法有什么区别
点个关注,必回关 文章目录一. execute和submit的区别与联系1、测试代码的整体框架如下:2、首先研究Future<?> submit(Runnable task)和void execute(Runnable command),3、submit(Runnable task, T result) 方法可以使submit执行完Run…...
Vue.extend和VueComponent的关系源码解析
目录 0.概念解释 前言 需求分析 Vue.extend 编程式的使用组件 源码分析 0.概念解释 Vue.extend和VueComponent是Vuejs框架中创建组件的两种不同方式。Vue.extend方法能够让你根据Vue对象(继承)来定义一个新的可重用的组件构造器。而VueComponent方…...

【动态规划】01背包问题(滚动数组 + 手画图解)
01背包除了可以用形象的二维动态数组表示外,还可以使用空间复杂度更低的一维滚动数组。 目录 文章目录 前言 一、滚动数组的基本理解 二、确定dp及其下标含义 三、确定递推公式 四、确定初始化 五、确定遍历顺序 1.用物品(正序)遍历背…...

javaEE 初阶 — 超时重传机制
文章目录超时重传机制1. 数据重复传输问题2. 如何解决数据重复传输问题3. 重传次数问题TCP 的工作机制:确认应答机制 超时重传机制 如果传输数据的时候丢包了该怎么办? 利用 超时重传,也就是超过了一定的时间,如果还没响应就重新…...
小米5x wlan无法打开解决
诱因:想要利用空置设备做节点服务器或者边缘计算,因此解锁并刷了magisk,印象中在刷之前wlan已经无法打开无法进行wifi联网 表现: 1 WLAN开关无法打开,或者虚假打开,无法扫描wifi 2 设置->我的设备->全…...
负载均衡之最小活跃数算法
文章目录[toc]一、概念二、场景与设计思路三、实现四、代码下载一、概念 活跃数 集群中各实例未处理的请求数。 最小活跃数 集群中各个实例,哪个实例未处理的请求数据最小,就称之为最小活跃数。 二、场景与设计思路 场景 以获取微服务地址为场景。 设计…...

JavaScript 评测代码运行速度的几种方法
一、使用 performance.now() API 在 JavaScript 中,可以使用 performance.now() API 来评测代码的运行速度。该 API 返回当前页面的高精度时间戳,您可以在代码执行前后调用它来计算代码执行所需的时间。 例如: let t0 performance.now();…...

Linux 编译器 gcc/g++
本文已收录至《Linux知识与编程》专栏! 作者:ARMCSKGT 演示环境:CentOS 7 目录 前言 正文 gcc/g常用命令 自定义可执行程序名命令-o 预处理指令-E 编译指令-S 汇编指令-c 链接指令gcc 命令巧记口诀 链接库 动态库-动态链接 静态库…...

2.Java基础【Java面试第三季】
2.Java基础【Java面试第三季】前言推荐2.Java基础01_字符串常量Java内部加载-上58同城的java字符串常量池面试code讲解intern()方法---源码解释02_字符串常量Java内部加载-下whyOpenJDK8底层源码说明递推步骤总结考查点03_闲聊力扣算法第一题字节跳动两数求和题目说明面试题解法…...

Java高级-多线程
本篇讲解java多线程 基本概念: 程序、进程、线程 **程序(program)**是为完成特定任务、用某种语言编写的一组指令的集合。即指一段静态的代码,静态对象。 **进程(process)**是程序的一次执行过程,或是正在运行的一个程序。是一个动态的过程…...

mysql高级(事务、存储引擎、索引、锁、sql优化、MVCC)
文章目录1.事务1.1 四大特性ACID1.2 并发事务2.存储引擎2.1 InnoDB2.2 MyISAM2.3 Memory2.4 存储引擎特点2.5 存储引擎的选择3.性能分析3.1 查看执行频次3.2 慢查询日志3.3 profile3.4 explain4.索引4.1 索引结构B-TreeBTreeHash面试题4.2 索引分类思考题4.3 语法4.4 使用规则最…...

Java后端开发功能模块思路
文章目录前言一、查找接口及参数信息1.1 找访问路径1.2 参数及返回结果信息1.3 编写功能模块函数二、代码设计思路三、总结前言 对于正在学习Java后端开发的同学来说,对于Java后端功能模块的开发过程及思路要有一个整体清晰的流程。才能保证在开发过程中更加的顺畅…...

CAPL(vTESTStudio) - DoIP - TCP发送_05
TCP发送 参数定义 版本号:02 FD or 01 FE or 其他任意值数据类型:00 05 or 00 06 or 80 01 or其他任意值数据长度:想要发送的任意长度...

使用IntelliJ IDEA搭建datax-web开发环境
记录:372场景:使用IntelliJ IDEA搭建datax-web开发环境,以及datax-web基本使用。版本:JDK 1.8Python 2.7.5datax-web开源地址:https://github.com/WeiYe-Jing/datax-web1.配置Maven环境1.1安装目录目录:D:\…...

[SSD固态硬盘技术 14] GC垃圾回收太重要了
今天介绍臭名昭著的垃圾收集 过程(或“GC”),maybe 这是对JAVA 工程师而言。当遇到GC导致速度降低时候, 他们真的想跳脚。 我想到我的小孩打疫苗,哭的哇哇叫, 在他的眼里疫苗应该也是讨厌的吧, 但事实真的如此吗? 但首先,让我们考虑一下如果根本没有 GC,闪存系统会发…...

lamada表达式、stream、collect整理
lamada表达式格式 格式:( parameter-list ) -> { expression-or-statements } 实例:简化匿名内部类的写法 原本写法: public class LamadaTest { public static void main(String[] args) { new Thread(new Runnable() { …...

Nacos 入门微服务项目实战
Nacos 核心源码精讲 - IT贱男 - 掘金小册全方位源码精讲,深度剖析 Nacos 注册中心和配置中心的核心思想。「Nacos 核心源码精讲」由IT贱男撰写,375人购买https://s.juejin.cn/ds/BuC3Vs9/ Hi,大家好,欢迎大家来学习《Nacos 核心源…...

【c++】类和对象:让你明白“面向一个对象有多重要”:构造函数,析构函数,拷贝构造函数的深入学习
文章目录 什么是面向对象?一:类是什么? 1.类的访问限定符 2.封装 3.类的实例化 4.this指针二:类的6个默认成员函数 1.构造函数 2.析构函数 3.拷贝构造函数什么是面向对象? c语言是面向…...

职场IT老手教你3步教你玩转可视化大屏设计,让领导眼前一亮!
我是制造企业的IT中心的研发人员,平常工作就是配合业务部门出出报表,选型一些商业软件,并在内部负责实施运维。最近领导出去参观了一些数字化转型比较领先的工厂和制造企业,回来就甩给我几张图,问能不能我们也做几个这…...

【光伏功率预测】基于EMD-PCA-LSTM的光伏功率预测模型(Matlab代码实现)
💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式
一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明:假设每台服务器已…...
在软件开发中正确使用MySQL日期时间类型的深度解析
在日常软件开发场景中,时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志,到供应链系统的物流节点时间戳,时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库,其日期时间类型的…...

装饰模式(Decorator Pattern)重构java邮件发奖系统实战
前言 现在我们有个如下的需求,设计一个邮件发奖的小系统, 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其…...

【OSG学习笔记】Day 16: 骨骼动画与蒙皮(osgAnimation)
骨骼动画基础 骨骼动画是 3D 计算机图形中常用的技术,它通过以下两个主要组件实现角色动画。 骨骼系统 (Skeleton):由层级结构的骨头组成,类似于人体骨骼蒙皮 (Mesh Skinning):将模型网格顶点绑定到骨骼上,使骨骼移动…...

GC1808高性能24位立体声音频ADC芯片解析
1. 芯片概述 GC1808是一款24位立体声音频模数转换器(ADC),支持8kHz~96kHz采样率,集成Δ-Σ调制器、数字抗混叠滤波器和高通滤波器,适用于高保真音频采集场景。 2. 核心特性 高精度:24位分辨率,…...
AGain DB和倍数增益的关系
我在设置一款索尼CMOS芯片时,Again增益0db变化为6DB,画面的变化只有2倍DN的增益,比如10变为20。 这与dB和线性增益的关系以及传感器处理流程有关。以下是具体原因分析: 1. dB与线性增益的换算关系 6dB对应的理论线性增益应为&…...
C#学习第29天:表达式树(Expression Trees)
目录 什么是表达式树? 核心概念 1.表达式树的构建 2. 表达式树与Lambda表达式 3.解析和访问表达式树 4.动态条件查询 表达式树的优势 1.动态构建查询 2.LINQ 提供程序支持: 3.性能优化 4.元数据处理 5.代码转换和重写 适用场景 代码复杂性…...
适应性Java用于现代 API:REST、GraphQL 和事件驱动
在快速发展的软件开发领域,REST、GraphQL 和事件驱动架构等新的 API 标准对于构建可扩展、高效的系统至关重要。Java 在现代 API 方面以其在企业应用中的稳定性而闻名,不断适应这些现代范式的需求。随着不断发展的生态系统,Java 在现代 API 方…...

WPF八大法则:告别模态窗口卡顿
⚙️ 核心问题:阻塞式模态窗口的缺陷 原始代码中ShowDialog()会阻塞UI线程,导致后续逻辑无法执行: var result modalWindow.ShowDialog(); // 线程阻塞 ProcessResult(result); // 必须等待窗口关闭根本问题:…...

实战三:开发网页端界面完成黑白视频转为彩色视频
一、需求描述 设计一个简单的视频上色应用,用户可以通过网页界面上传黑白视频,系统会自动将其转换为彩色视频。整个过程对用户来说非常简单直观,不需要了解技术细节。 效果图 二、实现思路 总体思路: 用户通过Gradio界面上…...