# 线程池

# 线程池的背景

线程池是一种池化技术,实现了对于线程的复用。解决了线程数量不可控和线程频繁创建和销毁带来的开销。

# 线程池的参数

# 核心线程数量

不管任务数量,常驻的线程。

# 最大线程数量

当阻塞队列满之后,再有新任务加入,线程池就会在核心线程数量之外新创建线程(扩容),来执行新加入的任务。

# 阻塞队列

核心线程被用完后,新任务加入会进入阻塞队列。不同的阻塞队列

# 线程最大空闲时间

当非核心线程不执行任务超过这个时间,非核心线程就会被销毁,节约资源。

# 超时单位

# 拒绝策略

# 线程工厂

# 问题

# 为什么不建议使用Java自带的Executors创建线程池?

原因:线程池的参数不是由我们自己控制的。Java自带四种线程池,FixedThreadPool,SingleThreadExecutor,CachedThreadPool,ScheduledThreadPool。前两种线程池的阻塞队列长度为Integer.Max_VALUE,可能会堆积大量请求,导致OOM。后两种线程池最大线程数量为Integer.MAX_VALUE,可能会创建大量线程,导致OOM。

# 线程池参数应该如何设置

业务分为两种类型,计算密集型应用和IO密集型应用。

# 计算密集型应用

需要大量的CPU计算。虽然可以拆成多个任务执行,但切换成本过大。因此,最高效的方法是让同时执行的任务数量等于CPU的核心数量。

# IO密集型应用

涉及到IO操作(网络IO、磁盘IO)一般都是IO密集型应用。在这类场景下,CPU消耗很少,程序大部分时间都被IO操作阻塞。所以线程越多,CPU利用率越高。但线程过多会导致OOM。

# 计算公式

# IO密集型应用
最大线程数 = Ncpu / (1 - 阻塞系数)

阻塞系数需要采用性能分析工具或java.lang.management API来确定IO操作喻CPU米级人物所耗时间的比值,常见数值为0.7-0.9.如果任务计算式90%的时间双核CPU都在闲置,线程则应设置为20。

# 计算密集型应用
最大线程数 = Ncpu + 1

+1的原因:需要有一个核心完成线程上下文的调度

# 核心线程数
核心线程数 = 最大线程数 * 0.2

# 思想

# 生产者-消费者模型

可以把基于阻塞队列的生产者消费者模型放大一下,就是分布式消息队列。而这个模型就是线程级别的消息队列。

# 扩容与缩容

# 拒绝策略

保证系统的安全性。

Last Updated: 7/22/2024, 6:07:35 PM