当前位置: 首页 > news >正文

线程池与并发工具:优化多线程执行!

全文目录:

    • 开篇语
    • 前序
    • 前言
    • 第一部分:Executor框架与线程池
      • 1.1 什么是Executor框架?
      • 1.2 创建线程池
        • 示例:创建一个固定大小的线程池
      • 1.3 线程池的优点
    • 第二部分:Callable与Future接口
      • 2.1 `Callable`接口与`Runnable`接口
        • 示例:使用`Callable`接口
      • 2.2 `Future`接口
        • 示例:使用`Future`检查任务状态
    • 第三部分:线程池的调优与管理
      • 3.1 线程池的调优
        • 示例:创建自定义线程池
    • 总结
    • 文末

开篇语

哈喽,各位小伙伴们,你们好呀,我是喵手。运营社区:C站/掘金/腾讯云/阿里云/华为云/51CTO;欢迎大家常来逛逛

  今天我要给大家分享一些自己日常学习到的一些知识点,并以文字的形式跟大家一起交流,互相学习,一个人虽可以走的更快,但一群人可以走的更远。

  我是一名后端开发爱好者,工作日常接触到最多的就是Java语言啦,所以我都尽量抽业余时间把自己所学到所会的,通过文章的形式进行输出,希望以这种方式帮助到更多的初学者或者想入门的小伙伴们,同时也能对自己的技术进行沉淀,加以复盘,查缺补漏。

小伙伴们在批阅的过程中,如果觉得文章不错,欢迎点赞、收藏、关注哦。三连即是对作者我写作道路上最好的鼓励与支持!

前序

在Java中,创建和管理线程是一个资源密集型的任务,尤其是在高并发的应用中。每次创建新线程都会消耗大量的时间和系统资源。为了避免这种性能瓶颈,Java提供了线程池和相关的并发工具。线程池通过复用现有的线程来执行多个任务,从而显著提高程序的执行效率,并减少系统资源的浪费。

本文将介绍Executor框架线程池的使用,以及CallableFuture接口的使用方式。


前言

线程池是多线程编程中不可或缺的工具,它能够有效地管理线程的生命周期,避免频繁创建和销毁线程的开销,提升并发程序的性能。在Java中,Executor框架提供了非常灵活且强大的线程池管理功能。通过使用线程池,我们可以轻松地控制任务的执行,管理线程,处理任务的返回值。


第一部分:Executor框架与线程池

1.1 什么是Executor框架?

Executor框架是Java 5引入的一种用于处理并发任务的高级框架,它通过ExecutorExecutorServiceScheduledExecutorService接口来提供线程池管理功能。与传统的线程管理方法相比,Executor框架简化了线程的创建、调度和管理过程。

Executor框架主要包括以下几种组件:

  • Executor接口:是所有线程池的父接口,提供了一个执行任务的标准方法execute(Runnable command)
  • ExecutorService接口:继承自Executor,添加了用于管理任务生命周期的方法,如submit()shutdown()等。
  • ScheduledExecutorService接口:继承自ExecutorService,提供了定时和周期性任务的调度能力。

1.2 创建线程池

Java提供了Executors类来创建不同类型的线程池。常见的线程池包括:

  • FixedThreadPool:一个固定大小的线程池,适用于任务数量固定且大小合适的场景。
  • CachedThreadPool:一个可缓存的线程池,根据需要创建新线程,适用于执行许多短期异步任务。
  • SingleThreadExecutor:一个单线程的线程池,适用于顺序执行任务的场景。
示例:创建一个固定大小的线程池
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class ExecutorExample {public static void main(String[] args) {// 创建一个固定大小的线程池ExecutorService executorService = Executors.newFixedThreadPool(3);// 提交多个任务for (int i = 0; i < 5; i++) {executorService.submit(() -> {System.out.println(Thread.currentThread().getName() + " is executing a task.");});}// 关闭线程池executorService.shutdown();}
}

解释:

  • Executors.newFixedThreadPool(3)创建了一个大小为3的线程池。
  • submit()方法将任务提交给线程池进行执行。线程池会根据可用线程执行任务。
  • 最后调用shutdown()方法关闭线程池,等待所有任务执行完毕。

1.3 线程池的优点

  • 提高性能:线程池通过复用线程来执行多个任务,避免了频繁创建和销毁线程的开销。
  • 管理线程:线程池可以动态调整线程数量,处理不同类型的任务。
  • 避免资源浪费:线程池合理地管理线程,避免了创建过多线程而导致的系统资源浪费。

第二部分:Callable与Future接口

2.1 Callable接口与Runnable接口

RunnableCallable都是用于定义任务的接口,但它们有几个不同之处:

  • Runnable:没有返回值,run()方法不抛出异常。
  • Callable:有返回值,call()方法可以返回结果,并且可以抛出异常。

Callable接口是ExecutorService框架中用来执行任务并获取返回值的标准接口。相比RunnableCallable更加灵活,适合需要返回结果或者处理异常的任务。

示例:使用Callable接口
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;public class CallableExample {public static void main(String[] args) throws Exception {// 创建一个固定大小的线程池ExecutorService executorService = Executors.newFixedThreadPool(2);// 创建一个Callable任务Callable<Integer> task = () -> {System.out.println(Thread.currentThread().getName() + " is executing a task.");return 42;  // 返回任务的结果};// 提交任务并获取Future对象Future<Integer> future = executorService.submit(task);// 获取任务的结果Integer result = future.get();  // 阻塞直到任务完成System.out.println("Task result: " + result);// 关闭线程池executorService.shutdown();}
}

解释:

  • Callable<Integer> task是一个任务,它返回一个Integer类型的结果。
  • submit()方法提交任务并返回一个Future对象,通过Future.get()方法可以获取任务的执行结果。如果任务还没有完成,get()方法会阻塞直到任务完成。
  • shutdown()方法关闭线程池。

2.2 Future接口

Future接口用于表示异步计算的结果。通过Future对象,我们可以检查任务是否完成、取消任务,或者获取任务的结果。Future接口常用于异步任务的执行。

常用的方法:

  • get():阻塞并等待任务完成,返回任务的结果。
  • isDone():检查任务是否完成。
  • cancel(boolean mayInterruptIfRunning):取消任务的执行。
示例:使用Future检查任务状态
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;public class FutureExample {public static void main(String[] args) throws Exception {ExecutorService executorService = Executors.newFixedThreadPool(2);// 创建一个Callable任务Callable<String> task = () -> {Thread.sleep(2000);  // 模拟长时间运行的任务return "Task completed!";};Future<String> future = executorService.submit(task);// 检查任务是否完成while (!future.isDone()) {System.out.println("Task is still running...");Thread.sleep(500);}// 获取任务的结果System.out.println(future.get());  // 输出:Task completed!executorService.shutdown();}
}

解释:

  • future.isDone()方法用于检查任务是否完成。如果任务还在执行,isDone()返回false,否则返回true
  • future.get()方法会阻塞直到任务完成并返回任务的结果。

第三部分:线程池的调优与管理

3.1 线程池的调优

线程池的性能调优涉及多个方面,包括线程池的大小、任务队列的配置以及拒绝策略等。合理配置线程池能够提高并发性能,避免线程池资源浪费或线程过多导致的性能问题。

常见的调优参数:

  • 核心池大小corePoolSize):线程池的核心线程数量。如果线程池中没有空闲线程,且提交的任务数量超过核心线程数,线程池将创建新的线程(最多到最大线程数)。
  • 最大池大小maximumPoolSize):线程池中允许的最大线程数。
  • 线程空闲时间keepAliveTime):如果线程池中的线程数超过核心线程数,空闲线程在多长时间后会被销毁。
  • 任务队列BlockingQueue):线程池使用队列来存放等待执行的任务。常见的队列类型有ArrayBlockingQueueLinkedBlockingQueue等。
示例:创建自定义线程池
import java.util.concurrent.*;public class CustomThreadPoolExample {public static void main(String[] args) {// 创建一个带有自定义配置的线程池ExecutorService executorService = new ThreadPoolExecutor(2,  // corePoolSize4,  // maximumPoolSize60L, TimeUnit.SECONDS,  // keepAliveTimenew ArrayBlockingQueue<>(10),  // workQueuenew ThreadPoolExecutor.CallerRunsPolicy()  // Rejection policy);for (int i = 0; i < 10; i++) {executorService.submit(() -> {System.out.println(Thread.currentThread().getName() + " is executing task.");});}executorService.shutdown();}
}

解释:

  • corePoolSize设置为2,maximumPoolSize设置为4,线程池的大小将在这两个范围之间动态调整。
  • keepAliveTime设置为60秒,空闲线程在60秒后被销毁。
  • 使用ArrayBlockingQueue作为任务队列,队列容量为10。
  • CallerRunsPolicy是一个拒绝策略,当任务数量超出最大线程池容量时,当前调用线程会执行任务,而不是将任务丢弃或抛出异常。

总结

Java的Executor框架和线程池提供了一个高效的方式来管理多线程任务。通过使用ExecutorService创建线程池,我们可以有效地管理线程的生命周期,提高系统的并发能力。CallableFuture接口为我们提供了一个强大的异步编程机制,允许我们在执行任务时获取结果并检查任务状态。

合理调优线程池的配置,可以进一步提高程序的性能和稳定性。通过掌握这些并发工具,我们可以在高并发场景下写出更加高效、稳定的代码。

… …

文末

好啦,以上就是我这期的全部内容,如果有任何疑问,欢迎下方留言哦,咱们下期见。

… …

学习不分先后,知识不分多少;事无巨细,当以虚心求教;三人行,必有我师焉!!!

wished for you successed !!!


⭐️若喜欢我,就请关注我叭。

⭐️若对您有用,就请点赞叭。
⭐️若有疑问,就请评论留言告诉我叭。


版权声明:本文由作者原创,转载请注明出处,谢谢支持!

http://www.dtcms.com/a/270634.html

相关文章:

  • [特殊字符]【跨数据库支持】SQL 秒转 ArkTS 实体!HarmonyOS 开发者的数据库适配神器 gotool.top
  • Node.Js是什么?
  • AI+智慧园区 | 事件处置自动化——大模型重构园区治理逻辑
  • 【图像处理基石】如何检测到画面中的ppt并对其进行增强?
  • 洛谷 P1104 生日---排序
  • Android Studio 2024,小白入门喂饭级教程
  • 滑动窗口的初步了解
  • 记录一下:成功部署k8s集群(部分)
  • 【音视频】TS协议介绍
  • 搭建商城系统
  • 【Java】【力扣】3.无重复字符的最长字串
  • Flutter基础(前端教程⑧-数据模型)
  • Elasticsearch RESTful API入门:基础搜索与查询DSL
  • C#项目 在Vue/React前端项目中 使用使用wkeWebBrowser引用并且内部使用iframe网页外链 页面部分白屏
  • 数据管理新范式:基于Docker的私有云存储系统构建指南
  • 十一、K8s细粒度权限管理RBAC
  • 异步进阶:C#的Task.WhenAll——如何开启多个异步任务
  • ReactNative【实战系列教程】我的小红书 6 -- 购物(含商品搜索、商品分类、商品列表)
  • 编写产品需求文档:黄历日历小程序
  • [Leetcode] 预处理 | 多叉树bfs | 格雷编码 | static_cast | 矩阵对角线
  • React面试高频考点解析
  • LeetCode Hot 100 搜索二维矩阵 II
  • langchain从入门到精通(四十一)——基于ReACT架构的Agent智能体设计与实现
  • [附源码+数据库+毕业论]基于Spring Boot+mysql+vue结合内容推荐算法的学生咨询系统
  • RedisCommandExecutionException: ERR unknown command ‘LPOS‘
  • 树莓派5-系统 Debian 12 开启VNC远程访问踩坑记录
  • vue3面试题(个人笔记)
  • uniapp AndroidiOS 定位权限检查
  • ragflow_多模态文档解析与正文提取策略
  • 《设计模式之禅》笔记摘录 - 5.代理模式