线程池的创建方法 总共有 7 种,但总体来说可分为 2 类:
  • 一类是通过 ThreadPoolExecutor 创建的线程池;
  • 另一个类是通过 Executors 创建的线程池。
1. Executors.newFixedThreadPool:创建一个固定大小的线程池,可控制并发的线程数,超出的线程会在队列中等待;
2. Executors.newCachedThreadPool:创建一个可缓存的线程池,若线程数超过处理所需,缓存一段时间后会回收,当执行第二个任务时第一个任务已经完成,
    会复用执行第一个任务的线程,若线程数不够,则一直新建线程;
3. Executors.newSingleThreadExecutor:创建单个线程数的线程池,它可以保证先进先出的执行顺序;
4. Executors.newScheduledThreadPool:创建一个可以执行延迟任务的线程池;
5. Executors.newSingleThreadScheduledExecutor:创建一个单线程的可以执行延迟任务的线程池;
6. Executors.newWorkStealingPool:创建一个抢占式执行的线程池(任务执行顺序不确定),创建一个具有并行级别的work-stealing线程池,
  【JDK 1.8 添加】可以传入线程的数量,不传入,则默认使用当前计算机中可用的cpu数量,能够合理的使用CPU进行对任务操作(并行操作),适合使用在很耗时的任务中。
7. ThreadPoolExecutor:最原始的创建线程池的方式,它包含了 7 个参数可供设置,后面会详细讲。
例如:
   ThreadPoolExecutor threadPool = new ThreadPoolExecutor(5, 50, 100, TimeUnit.SECONDS, new LinkedBlockingQueue<>(1000));
最大线程数:50: 排队队列最大数:1000
当线程池中正在使用的线程数达到了设置的最大的值(50),而且队列已(1000),还有数据进来的话就会报错。
即: 最大排队数 LinkedBlockingQueue要给一个总得要处理的预估数,比如处理100w的数据。
 
【推荐】线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。
说明:Executors 返回的线程池对象的弊端如下:
1) FixedThreadPool 和 SingleThreadPool:允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM。
2)CachedThreadPool:允许的创建线程数量为 Integer.MAX_VALUE,可能会创建大量的线程,从而导致 OOM。
3)也就是说如果执行的job很慢,就尽量不要使用上述2种线程池。相反的,如果处理很快的job,则可以使用。
 
参数 1:corePoolSize
核心线程数,线程池中始终存活的线程数。
参数 2:maximumPoolSize
最大线程数,线程池中允许的最大线程数,当线程池的任务队列满了之后可以创建的最大线程数。
参数 3:keepAliveTime
最大线程数可以存活的时间,当线程中没有任务执行时,最大线程就会销毁一部分,最终保持核心线程数量的线程。
参数 4:unit:
单位是和参数 3 存活时间配合使用的,合在一起用于设定线程的存活时间
参数 5:workQueue
一个阻塞队列,用来存储线程池等待执行的任务,均为线程安全,它包含以下 7 种类型:
  • ArrayBlockingQueue:一个由数组结构组成的有界阻塞队列。
  • LinkedBlockingQueue:一个由链表结构组成的有界阻塞队列。
  • SynchronousQueue:一个不存储元素的阻塞队列,即直接提交给线程不保持它们。
  • PriorityBlockingQueue:一个支持优先级排序的无界阻塞队列。
  • DelayQueue:一个使用优先级队列实现的无界阻塞队列,只有在延迟期满时才能从中提取元素。
  • LinkedTransferQueue:一个由链表结构组成的无界阻塞队列。与SynchronousQueue类似,还含有非阻塞方法。
  • LinkedBlockingDeque:一个由链表结构组成的双向阻塞队列。
较常用的是 LinkedBlockingQueue 和 Synchronous,线程池的排队策略使用场景:
ArrayBlockingQueue预先分配好一段连续内存,更稳定
LinkedBlockingQueue 读写锁分离,吞吐量更大
参数 6:ThreadFactory
线程工厂,主要用来创建线程,默认为正常优先级、非守护线程。
参数 7:RejectedExecutionHandler
拒绝策略,拒绝处理任务时的策略,系统提供了 4 种可选:
  • AbortPolicy:拒绝并抛出异常。
  • CallerRunsPolicy:使用当前调用的线程来执行此任务。
  • DiscardOldestPolicy:抛弃队列头部(最旧)的一个任务,并执行当前任务。
  • DiscardPolicy:忽略并抛弃当前任务。
默认策略为 AbortPolicy
/**
* @Author Tim
* @Date 2022/6/15 16:03
*/
@Service
public class MultiThreadServiceImpl {
@Autowired
private UserInfoMapper userInfoMapper; /**
* 1.处理速度一般,并且是从回收的线程池中拿出原来的线程复用的.
* 如果执行的job很慢,就尽量不要使用这种线程池。相反的,如果job处理很快,则可以使用。
*/
private static final ExecutorService executorService = Executors.newCachedThreadPool(new BasicThreadFactory.Builder()
.namingPattern("create-card-thread-%d").build()); /**
* 2.处理速度较快,创建一个具有并行级别的work-stealing线程池。 parallelism: 并发级别,适合使用在很耗时的任务中
*/
private static final ExecutorService newWorkStealingPool = Executors.newWorkStealingPool(); /**
* 3.处理速度较快,核心线程数:10, 最大活跃数:50, 最大线程数可以存活的时间:60s, 用来存储线程池等待执行的任务数:100w
* 在不配置RejectedExecutionHandler的情况下,如果实际处理数100w超过了设置队列等待数Queue,会抛异常。
*/
private static final ThreadPoolExecutor threadPoolLocal =
new ThreadPoolExecutor(10, 20, 20, TimeUnit.SECONDS, new LinkedBlockingDeque<Runnable>(1000000)); /**
* 3. 参数不同。
* 配置RejectedExecutionHandler的情况下,不会报错,CallerRunsPolicy:使用当前调用的线程来执行此任务。
*/
private ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 20, TimeUnit.SECONDS,
new ArrayBlockingQueue(20, true), new ThreadPoolExecutor.CallerRunsPolicy()); public void insertUsersByThreads() {
for (int i = 0; i < 1000000; i++) {
//第二种
// CompletableFuture.runAsync(() -> {
// UserInfoPO userInfoPO = new UserInfoPO();
// userInfoPO.setUserEmail("testEmail");
// userInfoPO.setUserName(RandomStringUtils.randomNumeric(4));
// userInfoPO.setUserId(RandomStringUtils.randomNumeric(4));
// userInfoPO.setUserSex("boy");
// System.out.println("userInfoPO....." + userInfoPO.toString());
// userInfoMapper.insert(userInfoPO);
// }, newWorkStealingPool);
//第三种
newWorkStealingPool.execute(() ->{
UserInfoPO userInfoPO = new UserInfoPO();
userInfoPO.setUserEmail("testEmail");
userInfoPO.setUserId(RandomStringUtils.randomNumeric(8));
userInfoPO.setUserName(RandomStringUtils.randomNumeric(8));
userInfoPO.setUserSex("boy");
System.out.println("userInfoPO....." + userInfoPO.toString());
userInfoMapper.insert(userInfoPO);
});
//第一种
// CompletableFuture.runAsync(() -> {
// UserInfoPO userInfoPO = new UserInfoPO();
// userInfoPO.setUserEmail("testEmail");
// userInfoPO.setUserName(RandomStringUtils.randomNumeric(4));
// userInfoPO.setUserId(RandomStringUtils.randomNumeric(4));
// userInfoPO.setUserSex("boy");
// System.out.println("userInfoPO....." + userInfoPO.toString());
// userInfoMapper.insert(userInfoPO);
// }, executorService); }
}

springboot线程池的使用方式1的更多相关文章

  1. [开源项目]可观测、易使用的SpringBoot线程池

    在开发spring boot应用服务的时候,难免会使用到异步任务及线程池.spring boot的线程池是可以自定义的,所以我们经常会在项目里面看到类似于下面这样的代码 @Bean public Ex ...

  2. SpringBoot线程池和Java线程池的实现原理

    使用默认的线程池 方式一:通过@Async注解调用 public class AsyncTest { @Async public void async(String name) throws Inte ...

  3. springboot 线程池

    我们常用ThreadPoolExecutor提供的线程池服务,springboot框架提供了@Async注解,帮助我们更方便的将业务逻辑提交到线程池中异步执行,今天我们就来实战体验这个线程池服务: 本 ...

  4. springboot线程池的使用和扩展(转)

    springboot线程池的使用和扩展 我们常用ThreadPoolExecutor提供的线程池服务,springboot框架提供了@Async注解,帮助我们更方便的将业务逻辑提交到线程池中异步执行, ...

  5. springboot线程池的使用和扩展

    我们常用ThreadPoolExecutor提供的线程池服务,springboot框架提供了@Async注解,帮助我们更方便的将业务逻辑提交到线程池中异步执行,今天我们就来实战体验这个线程池服务: 本 ...

  6. springboot线程池@Async的使用和扩展

    我们常用ThreadPoolExecutor提供的线程池服务,springboot框架提供了@Async注解,帮助我们更方便的将业务逻辑提交到线程池中异步执行,今天我们就来实战体验这个线程池服务: 本 ...

  7. 【Java分享客栈】SpringBoot线程池参数搜一堆资料还是不会配,我花一天测试换你此生明白。

    一.前言   首先说一句,如果比较忙顺路点进来的,可以先收藏,有时间或用到了再看也行:   我相信很多人会有一个困惑,这个困惑和我之前一样,就是线程池这个玩意儿,感觉很高大上,用起来很fashion, ...

  8. SpringBoot线程池的创建、@Async配置步骤及注意事项

    最近在做订单模块,用户购买服务类产品之后,需要进行预约,预约成功之后分别给商家和用户发送提醒短信.考虑发短信耗时的情况所以我想用异步的方法去执行,于是就在网上看见了Spring的@Async了. 但是 ...

  9. springboot线程池任务调度类 -- ThreadPoolTaskScheduler介绍

    springboot中有一个bean,ThreadPoolTaskScheduler,可以很方便的对重复执行的任务进行调度管理:相比于通过java自带的周期性任务线程池ScheduleThreadPo ...

  10. Springboot 线程池配置

    最近的项目里要手动维护线程池,然后看到一起开发的小伙伴直接用Java了,我坚信Springboot不可能没这功能,于是查了些资料,果然有,这里给一下. 首先我们都知道@Async标签能让方法异步执行, ...

随机推荐

  1. 使用 Kubernetes 为 CI/CD 流水线打造高效可靠的临时环境

    介绍 在不断发展的科技世界中,快速构建高质量的软件至关重要.在真实环境中测试应用程序是及早发现和修复错误的关键.但是,在真实环境中设置 CI/CD 流水线进行测试可能既棘手又昂贵. Kubernete ...

  2. IoC入门案例

    1.管理什么?(Service和Dao) 2.如何将被管理的对象告知IoC容器?(配置) 3.被管理的对象交给IoC容器,如何获取IoC容器?(接口) 4.IoC容器得到后,如何从容器中获取到bean ...

  3. LeetCode224:基本计算器(栈)

    解题思路: 1.双栈模拟,一个用来存数,一个用来存操作符.需要考虑 '('后面紧跟'+'.'-'这种情况 2.递归:遇到左括号开始递归,遇到右括号结束递归,返回值. 1 class Solution: ...

  4. 组合式api-侦听器watch的语法

    和vue2对比,也是语法上稍有不同. 监听单个数据对象 <script setup> import {ref, watch} from "vue"; const cou ...

  5. Scrapy在pipeline中集成mongodb

    settings.py中设置配置项 MONGODB_HOST = "127.0.0.1" MONGODB_PORT = 27017 MONGODB_DB_NAME = " ...

  6. 架构与思维:如何应对Redis热Key?

    ★ Redis系列文章 Redis系列1:深刻理解高性能Redis的本质 Redis系列2:数据持久化提高可用性 Redis系列3:高可用之主从架构 Redis系列4:高可用之Sentinel(哨兵模 ...

  7. IDM HOSTS本地注册 屏蔽的网址

    127.0.0.1 registeridm.com127.0.0.1 www.registeridm.com127.0.0.1 www.internetdownloadmanager.com127.0 ...

  8. Ubuntu 下建立 eclipse 启动图标,解决ADT没有菜单栏问题(转载)

    原文地址 怎么在这应用程序里边建立图标$sudo gedit /usr/share/applications/Eclipse.desktop输入以下代码 [Desktop Entry]Name=Ecl ...

  9. 解决 cv2.destroyAllWindows() 无效问题

    方法一 示例代码: import cv2 import numpy as npimg = np.zeros((512,512),np.uint8)#生成一个空灰度图像 cv2.line(img,(0, ...

  10. 【开源项目】轻量元数据管理解决方案——Marquez

    大家好,我是独孤风. 又到了本周的开源项目推荐.最近推荐的元数据管理项目很多,但是很多元数据管理平台的功能复杂难用. 那么有没有轻量一点的元数据管理项目呢? 今天为大家推荐的开源项目,就是一个轻量级的 ...