Java ExecutorService:你真的了解它吗?

在这里插入图片描述

文章目录

    • 一、什么是ExecutorService?
    • 二、ExecutorService的核心功能
    • 三、如何创建和使用ExecutorService?

时光匆匆,又来到另一个里程碑,感谢粉丝们的陪伴,有你们真好~
不水文啦,一起加油叭~

一、什么是ExecutorService?

ExecutorService 是 Java 中用来管理和执行多线程任务的一种高级工具。可以有效地管理线程的生命周期和任务的执行过程,特别是在需要处理大量并发任务时尤为有用。

生动形象的比喻,ExecutorService 就像是一个管理者,你可以把任务交给它,它会根据需要创建线程,并且确保任务按照你的要求执行。

在实际编程中,可以通过 ExecutorService 来避免直接操作线程,这样做通常更安全和更高效。

可以创建一个 ExecutorService 并告诉它需要执行的任务,ExecutorService 会根据需要创建线程,并在执行完任务后将线程回收以便重用,这样可以节省资源并提高性能。

看一个简单的例子:

假设有一个需要处理大量数据的任务,可以创建一个 ExecutorService,并告诉它希望同时执行多少个任务。ExecutorService 会根据设定的自动创建和管理线程,确保这些任务可以并发执行而不会互相干扰。这种方式比手动管理线程更容易,并且可以更好地利用计算机的多核处理能力。

// 创建一个固定大小的线程池,最多同时执行两个任务
ExecutorService executor = Executors.newFixedThreadPool(2);// 提交两个任务给线程池执行
executor.submit(() -> {System.out.println("任务1 正在执行...");// 这里放置任务1的具体代码逻辑
});executor.submit(() -> {System.out.println("任务2 正在执行...");// 这里放置任务2的具体代码逻辑
});// 关闭线程池
executor.shutdown();

二、ExecutorService的核心功能

  1. 创建固定大小的线程池
// 创建一个包含5个线程的固定大小线程池
ExecutorService executor = Executors.newFixedThreadPool(5); 

使用场景: 当需要限制同时执行的线程数量时,可以使用固定大小的线程池。这样可以控制并发线程数量,避免系统资源被过度消耗。

  1. 创建可缓存的线程池
// 创建一个可根据需要自动扩展的线程池
ExecutorService executor = Executors.newCachedThreadPool(); 

使用场景: 当有大量短期异步任务需要处理时,可以使用可缓存线程池。它会根据任务的增加自动创建新线程,并在空闲时重用现有线程,从而提高性能。

  1. 提交 Runnable 任务
executor.submit(() -> {System.out.println("执行任务1");// 这里放置任务1的具体代码逻辑
});

使用场景: 当需要执行没有返回值的简单任务时,可以提交实现了 Runnable 接口的任务。例如,清理临时文件、发送通知等异步操作。

  1. 提交 Callable 任务并获取结果
Future<Integer> future = executor.submit(() -> {System.out.println("执行任务2");// 这里放置任务2的具体代码逻辑// 返回任务执行结果return fu;  
});try {// 获取任务执行结果,可能会阻塞直到任务完成Integer result = future.get();  System.out.println("任务2 的结果是:" + result);
} catch (InterruptedException | ExecutionException e) {e.printStackTrace();
}

使用场景: 当需要执行有返回值的任务,并且可能需要等待任务完成后获取结果时,可以提交实现了 Callable 接口的任务,并使用 Future 对象获取任务的返回值。

扩展:

Future 接口提供了一个特殊的阻塞方法 get(),它返回 Callable 任务执行的实际结果,但如果是 Runnable 任务,则只会返回 null。

如果调用get()方法时任务仍在运行,那么调用将会一直被执阻塞,直到任务正确执行完毕并且结果可用时才返回。

get() 方法是阻塞的,而且并不知道要阻塞多长时间。因此可能导致应用程序的性能降低。如果结果数据并不重要,那么我们可以使用超时机制来避免长时间阻塞。

// 等待 200 毫秒
String result = future.get(200, TimeUnit.MILLISECONDS);

这个get() 的重载,第一个参数为超时的时间,第二个参数为时间的单位。

  1. 控制线程池的关闭
// 平稳关闭线程池,等待所有任务执行完成
executor.shutdown(); 

使用场景: 当不再需要使用 ExecutorService 时,应该调用 shutdown() 方法来关闭线程池。确保已提交的任务能够完成执行,避免资源泄漏和任务丢失的问题。

三、如何创建和使用ExecutorService?

使用 Executors 工厂类来创建不同类型的 ExecutorService。

newFixedThreadPool(int n) 可以创建一个固定大小的线程池。

newCachedThreadPool() 则可以创建一个根据需要自动扩展的线程池。

实际案例:

创建一个简单的多线程程序,使用 ExecutorService 执行一批任务,并获取它们的执行结果。

public static void main(String[] args) {// 创建一个固定大小为3的线程池ExecutorService executor = Executors.newFixedThreadPool(3);// 创建一个列表来保存提交的任务List<Future<Integer>> futures = new ArrayList<>();// 提交10个任务,每个任务返回任务ID乘以2的结果for (int i = 1; i <= 10; i++) {final int taskId = i;// 提交 Callable 任务,并将 Future 对象保存到列表中Future<Integer> future = executor.submit(() -> {System.out.println("任务 " + taskId + " 开始执行");// 模拟任务执行耗时Thread.sleep(2000);  // 返回任务的结果return taskId * 2;   });// 将 Future 对象添加到列表中futures.add(future);  }// 等待所有任务完成,并打印各任务的执行结果for (Future<Integer> future : futures) {try {// 获取任务执行结果,可能会阻塞直到任务完成Integer result = future.get();  System.out.println("任务结果: " + result);} catch (InterruptedException | ExecutionException e) {e.printStackTrace();}}// 关闭线程池executor.shutdown();}// 输出结果
任务 1 开始执行
任务 2 开始执行
任务 3 开始执行
任务结果: 2
任务结果: 4
任务 4 开始执行
任务结果: 6
任务 5 开始执行
任务结果: 8
任务 6 开始执行
任务结果: 10
任务 7 开始执行
任务结果: 12
任务 8 开始执行
任务结果: 14
任务 9 开始执行
任务结果: 16
任务 10 开始执行
任务结果: 18
任务结果: 20

时间不能增添一个人的生命,然而珍惜光阴却可使生命变得更有价值

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/392222.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C语言基础知识点(十三)结构体的深拷贝与浅拷贝

在C或C等语言中&#xff0c;结构体&#xff08;Struct&#xff09;是一种用户自定义的数据类型&#xff0c;它允许将不同类型的数据项组合成一个单一的类型。对于结构体的拷贝&#xff0c;存在深拷贝&#xff08;Deep Copy&#xff09;和浅拷贝&#xff08;Shallow Copy&#x…

2024年,pdf文献热门翻译软件总结推荐

对于如今的时代&#xff0c;市面上存在各式各样的学术资料&#xff0c;对于没有语言天赋的我&#xff0c;看得眼花缭乱。看个学术资料都不知道要用哪个工具&#xff0c;试来试去和睦浪费时间。今天就我使用过的翻译软件中&#xff0c;整理了四款能帮助我们解决文献翻译难题的四…

免费自动化AI视频剪辑工具

下载地址&#xff1a;https://pan.quark.cn/s/3c5995da512e FunClip是一款完全开源、本地部署的自动化视频剪辑工具&#xff0c;通过调用阿里巴巴通义实验室开源的FunASR Paraformer系列模型进行视频的语音识别&#xff0c;随后用户可以自由选择识别结果中的文本片段或说话人&…

RocketMQ5.0 生产者

生产者消息类型&#xff1a; ​​​​​​​ 延迟队列的生产者 package mainimport ("context""fmt""github.com/apache/rocketmq-clients/golang/v5""github.com/apache/rocketmq-clients/golang/v5/credentials"errgroup2 "go…

学习记录——day26 进程间的通信(IPC)无名管道 无名管道 信号通信 特殊的信号处理

目录 一、进程间通信引入 二、无名管道 1、无名管道相关概念 2、无名管道的API接口函数 pipe(int pipefd[2]); 3、管道通信的特点 4、管道的读写特点 三、无名管道 1、有名管道&#xff1a;有名字的管道文件&#xff0c;其他进程可以调用 2、可以用于亲缘进程间的通信&…

代码随想录训练营第五十二天 孤岛的总面积

第一题&#xff1a;孤岛的总面积 第二题&#xff1a;沉没孤岛 思路&#xff1a; 将所有在边界的岛屿所在的visited数组位置都置为true&#xff0c;剩下的visited[i][j] true && grid[i][j] 1的位置就是孤岛&#xff0c;将其置为1即可。 代码如下 #include <io…

【限免】通信信号与干扰信号【附MATLAB代码】

微信公众号&#xff1a;EW Frontier 关注可了解更多的雷达、通信、人工智能相关代码。问题或建议&#xff0c;请公众号留言; 个人博客&#xff1a;106.54.201.174 QQ交流群&#xff1a;949444104 摘要 本项目主要模拟仿真常见通信信号及干扰信号&#xff0c;高斯白噪声、噪声调…

NSF共享目录未授权访问

NSF共享目录未授权访问 Network File System(NFS)&#xff0c;是由SUN公司研制的UNIX表示层协议(pressentation layer protocol)&#xff0c;能使使用者访问网络上别处的文件就像在使用自己的计算机一样。服务器在启用nfs服务以后&#xff0c;由于fs服务未限制对外访问&#x…

无人机之导航系统篇

一、导航系统组成 包括惯性导航系统、卫星导航系统、视觉导航系统等。 二、导航原理 利用传感器感知无人机的位置、速度和姿态信息&#xff0c;结合地图数据和导航算法&#xff0c;计算出无人机当前的位置和航向&#xff0c;从而引导无人机按照预设的航线飞行。 三、导航精…

使用SpringBoot+Vue3开发项目(2)---- 设计文章分类的相关接口及页面

目录 一.所用技术栈&#xff1a; 二.后端开发&#xff1a; 1.文章分类列表渲染&#xff1a; 2.新增文章分类&#xff1a; 3.编辑文章分类&#xff1a; 4.删除文章分类 &#xff1a; 5.完整三层架构后端代码&#xff1a; &#xff08;1&#xff09;Controller层&#xff1a…

优化if-else的11种方案

优雅永不过时&#xff01; 1. 使用早返回&#xff08;Early Return&#xff09;&#xff1a;尽可能早地返回&#xff0c;避免嵌套的if-else。 优化前&#xff1a; public class NoEarlyReturnExample {public boolean hasPositiveNumber(int[] numbers) {boolean foundPositi…

学习大数据DAY31 Python基础语法4和基于Python中的MySQL 编程

目录 Python 库 模块 time&datetime 库 连接 MySQL 操作 结构操作 数据增删改操作 数据查询操作 上机练习 7 面向对象 OOP 封装 继承 三层架构---面向对象思想模型层 数据层 业务逻辑显示层 上机练习 8 三层架构开发豆瓣网 关于我对 AI 写代码的看法&#xf…

客户数据分析模型:RFM模型的深度解析与应用探索

RFM模型&#xff0c;作为客户数据分析中的经典工具&#xff0c;凭借其简单而强大的分析能力&#xff0c;被广泛应用于各行各业。本文旨在深入探讨RFM模型的核心原理、应用价值&#xff0c;并详细阐述其在2C&#xff08;面向消费者&#xff09;和2B&#xff08;面向企业&#xf…

使用ThreadLocal来存取单线程内的数据

一.什么是ThreadLocal&#xff1f; ThreadLocal&#xff0c;即线程本地变量。如果你创建了一个 ThreadLocal变量&#xff0c;那么访问这个变量的每个线程都会有这个变量的一个本地拷贝&#xff0c;多个线程操作这个变量的时候&#xff0c;实际是在操作自己本地内存里面的变量&…

自注意力和位置编码

一、自注意力 1、给定一个由词元组成的输入序列x1,…,xn&#xff0c; 其中任意xi∈R^d&#xff08;1≤i≤n&#xff09;。 该序列的自注意力输出为一个长度相同的序列 y1,…,yn&#xff0c;其中&#xff1a; 2、自注意力池化层将xi当作key&#xff0c;value&#xff0c;query来…

Ubuntu配置carla docker环境

前言: 本文只在以下设备成功运行, 其他设备不保证能成功, 可以参考在自己设备进行配置 环境 ubuntu 20.04carla 0.9.15gpu 3060(notebook) 安装显卡驱动&nvidia-container-toolkit 显卡驱动 安装完成系统后直接在’软件和更新->附加驱动’直接选择470(proprietary…

Leetcode3227. 字符串元音游戏

Every day a Leetcode 题目来源&#xff1a;3227. 字符串元音游戏 解法1&#xff1a;博弈论 分类讨论&#xff1a; 如果 s 不包含任何元音&#xff0c;小红输。如果 s 包含奇数个元音&#xff0c;小红可以直接把整个 s 移除&#xff0c;小红赢。如果 s 包含正偶数个元音&am…

R 语言学习教程,从入门到精通,R 基础运算(5)

1、R 基础运算 本章介绍 R 语言的简单运算。 1.1、赋值 一般语言的赋值是 号&#xff0c;但是 R 语言是数学语言&#xff0c;所以赋值符号与我们数学书上的伪代码很相似&#xff0c;是一个左箭头 <- &#xff1a; a <- 123 b <- 456 print(a b)以上代码执行结果…

最好用的掏耳勺是哪种?年度五款可视挖耳勺高分机型

在我们的日常生活中&#xff0c;掏耳朵似乎是一件再平常不过的小事&#xff0c;不过&#xff0c;传统挖耳勺在使用时完全依赖我们的感觉和经验&#xff0c;我们无法直接看到耳道内部的情况。这就如同在黑暗中摸索&#xff0c;极易造成意外伤害。稍有不慎&#xff0c;就可能刮伤…

使用gitea私有仓库作为依赖

实际问题 由于公司团队使用gitea搭建了git私有仓库&#xff0c;在开发Go程序的时候会有一些公共代码&#xff0c;比如插件和主程序之间要共享接口和数据结构&#xff0c;所以就需要在gitea私有仓库中创建依赖仓库&#xff0c;然后其他仓库引用这个私有仓库作为依赖。 解决方案…