小蔡学Java

线程池的核心参数及实现原理

2023-12-25 14:08 1085 0 JVM / JUC 多线程线程池

说一下线程池的核心参数

  • corePoolSize 核心线程数目
  • maximumPoolSize 最大线程数目 = (核心线程+救急线程的最大数目)
  • keepAliveTime 生存时间 - 救急线程的生存时间,生存时间内没有新任务,此线程资源会释放
  • unit 时间单位 - 救急线程的生存时间单位,如秒、毫秒等
  • workQueue - 当没有空闲核心线程时,新来任务会加入到此队列排队,队列满会创建救急线程执行任务
  • threadFactory 线程工厂 - 可以定制线程对象的创建,例如设置线程名字、是否是守护线程等
  • handler 拒绝策略 - 当所有线程都在繁忙,workQueue 也放满时,会触发拒绝策略

线程池的执行原理

如果核心或临时线程执行完成任务后会检查阻塞队列中是否有需要执行的线程,如果有,则使用非核心线程执行任务

拒绝策略

1.AbortPolicy:直接抛出异常,默认策略; 2.CallerRunsPolicy:用调用者所在的线程来执行任务; 3.DiscardOldestPolicy:丢弃阻塞队列中靠最前的任务,并执行当前任务; 4.DiscardPolicy:直接丢弃任务;

线程池中有哪些常见的阻塞队列

workQueue - 当没有空闲核心线程时,新来任务会加入到此队列排队,队列满会创建救急线程执行任务

1.ArrayBlockingQueue:基于数组结构的有界阻塞队列,FIFO。 2.LinkedBlockingQueue:基于链表结构的有界阻塞队列,FIFO。 3.DelayedWorkQueue :是一个优先级队列,它可以保证每次出队的任务都是当前队列中执行时间最靠前的 4.SynchronousQueue:不存储元素的阻塞队列,每个插入操作都必须等待一个移出操作。

ArrayBlockingQueue的LinkedBlockingQueue区别

如何确定核心线程数

IO密集型任务 一般来说:文件读写、DB读写、网络请求等 核心线程数大小设置为2N+1

CPU密集型任务 一般来说:计算型代码、Bitmap转换、Gson转换等 核心线程数大小设置为N+1

查看机器的CPU核数

线程数的选择核心

① 高并发、任务执行时间短 ->( CPU核数+1 ),减少线程上下文的切换 ② 并发不高、任务执行时间长 IO密集型的任务 -> (CPU核数 * 2 + 1) 计算密集型任务 ->( CPU核数+1 ) ③ 并发高、业务执行时间长,解决这种类型任务的关键不在于线程池而在于整体架构的设计,看看这些业务里面某些数据是否能做缓存是第一步,增加服务器是第二步,至于线程池的设置,设置参考(2)

线程池的种类有哪些

在java.util.concurrent.Executors类中提供了大量创建连接池的静态方法,常见就有四种

  1. 创建使用固定线程数的线程池

  • 核心线程数与最大线程数一样,没有救急线程
  • 阻塞队列是LinkedBlockingQueue,最大容量为Integer.MAX_VALUE

适用情况 适用于任务量已知,相对耗时的任务

  1. 单线程化的线程池,它只会用唯一的工作线程来执行任 务,保证所有任务按照指定顺序(FIFO)执行

  • 核心线程数和最大线程数都是1
  • 阻塞队列是LinkedBlockingQueue,最大容量为Integer.MAX_VALUE

适用情况 适用于按照顺序执行的任务

  1. 可缓存线程池

  • 核心线程数为0
  • 最大线程数是Integer.MAX_VALUE
  • 阻塞队列为SynchronousQueue:不存储元素的阻塞队列,每个插入操作都必须等待一个移出操作。

适用情况 适合任务数比较密集,但每个任务执行时间较短的情况

  1. 提供了“延迟”和“周期执行”功能的ThreadPoolExecutor。

不建议用Executors创建线程池

阿里开发手册《Java开发手册-嵩山版》

线程池使用场景

  1. 在我们项目上线之前,我们需要把数据库中的数据一次性的同步到es索引库中,但是当时的数据好像是1000万左右,一次性读取数据肯定不行(oom异常),当时我就想到可以使用线程池的方式导入,利用CountDownLatch来控制,就能避免一次性加载过多,防止内存溢出

  1. 在一个电商网站中,用户下单之后,需要查询数据,数据包含了三部分:订单信息、包含的商品、物流信息;这三块信息都在不同的微服务中进行实现的,我们如何完成这个业务呢?

  • 在实际开发的过程中,难免需要调用多个接口来汇总数据,如果所有接口(或部分接口)的没有依赖关系,就可以使用线程池+future来提升性能
  • 报表汇总

  1. 异步保存

总结 (线程池的种类)

  • newFixedThreadPool:创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待
  • newSingleThreadExecutor:创建一个单线程化的线程池,它只会用唯一的工作线程来执行任 务,保证所有任务按照指定顺序(FIFO)执行
  • newCachedThreadPool:创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程
  • newScheduledThreadPool:可以执行延迟任务的线程池,支持定时及周期性任务执行

评论( 0 )

  • 博主 Mr Cai
  • 坐标 河南 信阳
  • 标签 Java、SpringBoot、消息中间件、Web、Code爱好者

文章目录