线程池ThreadPoolExecutor使用指南

在这里插入图片描述

线程池ThreadPoolExecutor使用指南

🧐使用线程池的好处是什么?

统一管理,减少资源获取创建的开销,提高利用率。

🔧线程池的参数

ThreadPoolExecutor​ 3 个最重要的参数:

  • corePoolSize​ : 任务队列未达到队列容量时,最大可以同时运行的线程数量。

  • maximumPoolSize​ : 任务队列中存放的任务达到队列容量的时候,当前可以同时运行的线程数量变为最大线程数。

  • workQueue​: 新任务来的时候会先判断当前运行的线程数量是否达到核心线程数,如果达到的话,新任务就会被存放在队列中

ThreadPoolExecutor​其他常见参数 :

  • keepAliveTime​:线程池中的线程数量大于 corePoolSize​ 的时候,如果这时没有新的任务提交,核心线程外的线程不会立即销毁,而是会等待,直到等待的时间超过了 keepAliveTime​才会被回收销毁。
  • unit​ : keepAliveTime​ 参数的时间单位。
  • threadFactory​ :executor 创建新线程的时候会用到。
  • handler​ :拒绝策略
🤔你是如何创建线程池的?为什么不建议直接用Executors​创建线程池?

一般不建议直接用Executors​创建线程池的,这种方式缓冲队列没有限制合适的大小(默认整形的最大值),处理不好会有OOM的风险。而是通过 ThreadPoolExecutor​ 构造函数的方式,这样的好处就是更加明确线程池的运行规则,规避资源耗尽的风险。

    public static ExecutorService newFixedThreadPool(int nThreads) {return new ThreadPoolExecutor(nThreads, nThreads,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());}
    public LinkedBlockingQueue() {this(Integer.MAX_VALUE);}
✨线程池的策略有哪些?

当前同时运行的线程数量达到最大线程数量并且队列也已经被放满了任务时:

常见的策略有拒绝策略:

  • AbortPolicy​ 抛出 RejectedExecutionException​来拒绝新任务的处理。

  • CallerRunsPolicy​:调用执行自己的线程运行任务,由主线程自己来执行这个任务。(不允许丢弃任务适合该策略)

不常见策略(了解既可):

  • ThreadPoolExecutor.DiscardPolicy​:不处理新任务,直接丢弃掉。
  • ThreadPoolExecutor.DiscardOldestPolicy​:此策略将丢弃最早的未处理的任务请求。
📌Springboot下使用示例

当您使用ThreadPoolTaskExecutor​配置线程池时,可以参考以下示例代码:

ThreadPoolConfig​类通过@Configuration​注解标记为配置类,并定义了一个名为taskExecutor​的Bean,类型为ThreadPoolTaskExecutor​。在taskExecutor()​方法中,设置了线程池的核心线程数为10,最大线程数为20,队列容量为30,线程名前缀为"MyThread-",然后调用initialize()​方法初始化线程池,并返回配置好的ThreadPoolTaskExecutor​实例

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;@Configuration
public class ThreadPoolConfig {@Beanpublic ThreadPoolTaskExecutor taskExecutor() {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();executor.setCorePoolSize(10); // 设置核心线程数executor.setMaxPoolSize(20); // 设置最大线程数executor.setQueueCapacity(30); // 设置队列容量executor.setThreadNamePrefix("MyThread-"); // 设置线程名前缀executor.initialize(); // 初始化线程池return executor;}
}

异步任务的地方注入TaskExecutor Bean,并调用其execute()方法来提交任务:


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;@Service
public class MyService {@Autowiredprivate ThreadPoolTaskExecutor taskExecutor;public void executeAsyncTask() {taskExecutor.execute(() -> {// 执行异步任务的逻辑System.out.println("Async task executed by thread: " + Thread.currentThread().getName());});}
}

然而,也有一些特殊场景下可能需要手动创建线程池实例:

  1. 定制化需求:如果需要对线程池进行高度定制,例如设置特定的线程池参数或使用特殊的线程工厂等,可能需要手动创建线程池实例。
  2. 独立使用:某些情况下,线程池只在一个特定的类或模块中使用,并且不需要在整个应用中共享,这时候手动创建线程池可能更合适。

大多数情况下建议将线程池实例交给Spring容器管理,以便统一管理和便于集成;如果手动创建了线程池实例,建议在某个特定的时机手动调用线程池的shutdown()​方法来优雅地关闭线程池,释放资源。

但这个特定时机怎么定义?使用CountDownLatch​或许可以符合你的场景。

CountDownLatch​的使用

CountDownLatch​ 的作用就是 允许 多个线程阻塞在一个地方,直到所有线程的任务都执行完毕。那么手动创建的线程就可以通过shutdown()​方法来优雅地关闭线程池了。

package com.fjh.demo.thread;import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/*** @ClassName: CustomThreadPoolExample* @Description: TODO 手动自定义创建线程池,CountDownLatch使用场景* @Author: fengjiahao* @Date: 2024/6/15 21:26*/
public class CustomThreadPoolExample {public static void main(String[] args) throws InterruptedException {int numThreads = 5;// 核心线程数int corePoolSize = 3;// 最大线程数int maxPoolSize = 5;// 线程空闲时间long keepAliveTime = 10;// 任务队列,使用有界队列ArrayBlockingQueueThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize, // 核心线程数maxPoolSize, // 最大线程数keepAliveTime, // 线程空闲时间TimeUnit.SECONDS, // 时间单位new ArrayBlockingQueue<>(3) // 任务队列);CountDownLatch latch = new CountDownLatch(numThreads);for (int i = 0; i < numThreads; i++) {int finalI = i;executor.execute(() -> {try {System.out.println("Thread【"+ finalI +"】 started execute: " + Thread.currentThread().getName());Thread.sleep(2000); // 模拟线程执行任务} catch (InterruptedException e) {e.printStackTrace();}finally{latch.countDown(); // 每个线程执行完成后调用countDown方法}System.out.println("Thread finished: " + Thread.currentThread().getName());});}latch.await(); // 等待所有线程执行完成System.out.println("All threads have finished. Continuing main thread.");executor.shutdown(); // 关闭线程池}
}
☕最后

其实java8中有更加优雅的方式处理这种场景CompletableFuture​,有兴趣的同学可以去了解下🙂

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

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

相关文章

docker login 报错: http: server gave HTTP response to HTTPS client

环境&#xff1a; 自建 Harbor、Docker 1. 问题分析 # 命令&#xff0c;这里用的是 IP&#xff0c;可以为域名 docker login -u test 172.16.51.182:31120 # 输入密码 Password:# 报错如下&#xff1a; Error response from daemon: Get "https://172.16.51.182:31120/…

HIVE及SparkSQL优化经验

简介 针对高耗跑批时间长的作业&#xff0c;在公司近3个月做过一个优化专项&#xff1b;优化成效&#xff1a;综合cpu、内存、跑批耗时减少均在65%以上&#xff1b; cpu和内存消耗指的是&#xff1a;vcoreseconds和memoryseconds 这里简单说下优化的一些思路&#xff0c;至于…

[Algorithm][贪心][增减字符串匹配][分发饼干][最优除法][跳跃游戏Ⅱ][跳跃游戏]详细讲解

目录 1.增减字符串匹配1.题目链接2.算法原理详解3.代码实现 2.分发饼干1.题目链接2.算法原理详解3.代码实现 3.最优除法1.题目链接2.算法原理详解3.代码实现 4.跳跃游戏 II1.题目链接2.算法原理详解3.代码实现 5.跳跃游戏1.题目链接2.算法原理详解3.代码实现 1.增减字符串匹配 …

图神经网络pytorch_geometric库之MessagePassing类

MessagePassing是图神经网络Python库pytorch_geometric(PyG)库里非常重要的一个基类&#xff0c;它可以用来创建消息传递图神经网络&#xff0c;pytorch_geometric里很多类比如图卷积层GCNConv和图注意力层GATConv都基于此类实现&#xff0c;我们也可以基于它来自定义图神经网络…

期末复习6--链表头插法(逆序)尾插法(顺序)---输出链表

头插法 #include <stdio.h> #include <stdlib.h>struct Node //定义结构体 {char data; //数据域struct Node * next; //指针域 };/* 请在这里填写答案 */void PrintList (struct Node * head) {struct Node * s;if(head NULL){printf("None&qu…

mybatisplus 笔记

int isDelete userRoleMapper.delete(new LambdaQueryWrapper<UserRole>().in(UserRole::getUserId, roleUserDTO.getUserId()).in(UserRole::getRoleId, roleUserDTO.getRoleId()));LambdaQueryWrapper<UserRole>: LambdaQueryWrapper 是 MyBatis Plus 提供的一个…

Apipost模拟HTTP客户端

模拟HTTP客户端的软件有很多&#xff0c;其中比较著名的就有API-FOX、POSTMAN。 相信很多小伙伴都使用POSTMAN。这篇博客主要介绍Apipost的原因是&#xff0c;Apipost无需下载&#xff0c;具有网页版。 APIFOX的站内下载&#xff1a; Api-Fox&#xff0c;类似于PostMan的软件…

时间复杂度和空间复杂度的深入解析

在算法和数据结构的学习中&#xff0c;时间复杂度和空间复杂度是两个至关重要的概念。它们分别用于衡量算法在执行过程中所需的计算资源&#xff08;时间&#xff09;和存储资源&#xff08;空间&#xff09;。以下&#xff0c;我们将从技术难点、面试官关注点、回答吸引力以及…

JavaFX 节点

JavaFX Node类javafx.scene.Node是添加到JavaFX 场景图的所有组件 的基类&#xff08;超类&#xff09; 。JavaFX Node 类是抽象的&#xff0c;因此你只需将 Node 类的子类添加到场景图中。场景图中的所有 JavaFX Node 实例共享一组由 JavaFX Node 类定义的公共属性。本 JavaFX…

毕节前端工程师前景怎么样:深入剖析与全面展望

毕节前端工程师前景怎么样&#xff1a;深入剖析与全面展望 在数字化浪潮的推动下&#xff0c;前端工程师作为连接技术与用户的桥梁&#xff0c;其职业前景备受关注。毕节地区的前端工程师同样面临着机遇与挑战并存的局面。那么&#xff0c;毕节前端工程师的前景究竟如何呢&…

【Ruby爬虫01】某吃瓜网站图片数据采集

介绍 由于最近在学习Ruby&#xff0c;写一个爬虫锻炼一下。涉及xml解析、多线程、xpath语法等基础知识。 实现代码 使用说明 使用前请先安装如下gem gem install nokogiri http openssl# nokogiri&#xff1a;一个解析xml和html的库&#xff0c;支持css、xpath语法 # htt…

一文了解Redis

一.什么是Redis 与MySQL一样&#xff0c;Redis也是客户端服务器结构的程序&#xff0c;是基于内存的键值对存储系统&#xff0c;属于NoSQL的一种。与很多键值对数据库不同的是&#xff0c;Redis 中的值可以是由 string&#xff08;字符串&#xff09;、hash&#xff08;哈希&a…

高速缓存是怎么让CPU找到地址内容的?

这个场景在性能优化下&#xff0c;应该很少会用到。但是还是总结一下。 Input: CPU给的一个地址&#xff0c;例如 0xffads1233423 Out: 这个地址上的值。 WORKFLOW CPU 问高速缓存&#xff0c;高速缓存会拿这个地址的中间几个位置&#xff0c;组成一个key高速缓存拿着这个ke…

数学中的虚数单位 i 和电学中的虚数单位 j

什么是虚数&#xff1f; 虚数是扩展实数概念的一类数&#xff0c;能够解决某些在实数范围内无法解决的问题。虚数的基本单位是 (i)&#xff0c;定义为&#xff1a; i − 1 i \sqrt{-1} i−1 ​ 这意味着 (i) 的平方是 -1&#xff1a; i 2 − 1 i^2 -1 i2−1 为什么需要虚…

【算法专题--链表】删除排序链表中的重复元素II -- 高频面试题(图文详解,小白一看就懂!!)

目录 一、前言 二、题目描述 三、解题方法 ⭐ 双指针 -- 采用 哨兵位头节点 &#x1f95d; 什么是哨兵位头节点&#xff1f; &#x1f34d; 解题思路 &#x1f34d; 案例图解 四、总结与提炼 五、共勉 一、前言 删除排序链表中的重复元素II元素这道题&#xff0c…

【JKI SMO】框架讲解(二)

JKI State Machine 讲解 将JKI State Machine 模板拖曳到程序框图中&#xff0c; 如下图&#xff0c; 此模板会默认放置一个OK按钮在前面板中&#xff0c;用于提示用户如何增加一个简单的用户事件去使用此框架。 “Event Structure”&#xff0c;Idle&#xff1a;此分支可以设…

【JS重点17】原型链(面试重点)

一&#xff1a;原型链底层原理 以下面一段代码为例&#xff0c;基于原型对象&#xff08;Star构造函数的原型对象&#xff09;的继承使得不同构造函数的原型对象关联在一起&#xff08;此处是最大的构造函数Object原型对象&#xff09;&#xff0c;并且这种关联的关系是一种链…

C#联合Halcon机器视觉框架源码—升级版

相较于之前的NxtVision&#xff0c;本软件代码架构更加合理&#xff0c;且新增ui设计器、原来的vb脚本改为C#脚本&#xff0c;并尝试将视觉与运动控制相结合&#xff0c;是一体化的框架。 对源码有需求的&#xff0c;订阅本专栏后&#xff0c;私信我领取。

活动集锦 | 英码科技积极参与行业盛会,AI赋能城市数字化转型

在当今数字经济时代&#xff0c;城市全域数字化转型已经成为提升城市管理效能、优化资源配置、推动经济发展的重要手段。英码科技始终致力于为企业打造高效、低成本的行业应用方案&#xff0c;助力企业实现数字化转型。近日&#xff0c;英码科技受邀参加了多场行业展示活动&…

华为OD刷题C卷 - 每日刷题 23(提取字符串中的最长表达式,模拟目录管理功能 - 完整实现)

1、提取字符串中的最长表达式 目标是从一个给定的字符串中提取出最长的合法简单数学表达式&#xff0c;并计算该表达式的值。如果存在多个同样长度的合法表达式&#xff0c;则选择第一个出现的表达式进行计算。 简单数学表达式的规则&#xff1a; 只包含0-9的数字和、-、*三种…