1、线程池核心参数
(1)核心线程数:核心线程数量,线程池中会存在这么多个线程,当线程数量(包含空闲线程)少于corePoolSize的时候,会优先创建新线程,可以设置allowCoreThreadTimeOut=true来让核心线程池中线程也移除
(2)最大线程数:线程池的最大容量,线程池中的线程数量不得超过这么多个,除非阻塞队列设置为无界的
(3)空闲线程存活时间:空闲线程存活时间,线程空闲超过这个时间的时候就会销毁
(4)unit: keepAliveTime的时间单位,分钟、秒等
(5)线程阻塞队列:阻塞队列,线程池从这个队列中取线程,可以设置的队列类型(容量为:capacity):
- ArrayBlockingQueue:有界阻塞队列,当线程数量n:corePoolSize <= n < maximumPoolSize 且 n >= capacity :创建新线程处理任务 当:n >= maximumPoolSize 且 n >= capacity 拒绝线程
- LinkedBlockingQueue: 无界队列,maximumPoolSize不起作用,会一直创建线程
- SynchronousQuene: 不缓存任务,直接调度执行,线程数超过 maximumPoolSize 则直接拒绝线程
- PriorityBlockingQueue: 带优先级的线程队列
(6)线程拒绝策略:
- AbortPolicy: 直接丢弃并抛出异常
- CallerRunsPolicy: 线程池没有关闭则直接调用线程的run方法
- DiscardPolicy: 直接丢弃任务
- DiscardOldestPolicy: 丢弃最早的任务,并尝试把当前任务加入队列
(7)创建线程时使用的工厂:创建线程时使用的工厂,可以对线程进行统一设置,如是否守护线程、线程名等
2、线程池参数设置一般性分析
(1)CPU密集型 最佳线程数=CPU 核数 +1
对于 CPU 密集型,多线程本质上是为了提升多核 CPU 的利用率,所以对于一个 4 核的 CPU,每个核一个线程,理论上创建 4 个线程就可以了,再多创建线程也只是增加线程切换的成本。
所以,对于 CPU 密集型场景,理论上“线程的数量 =CPU 核数”就是最合适的。不过在实际项目中,线程的数量一般会设置为“CPU 核数 +1”,这样的话,当线程因为偶尔的内存页失效或其他原因导致阻塞时,这个额外的线程可以顶上,从而保证 CPU 的利用率。
(2)IO密集型 最佳线程数=2*CPU核数
。
IO设备的读写速度远低于CPU的执行速度,所以IO密集型的任务执行时间要比CPU密集型长很多。而线程在处理 I/O 的时间段内不会占用 CPU 来处理,这时就可以将 CPU 交出给其它线程使用。因此在 I/O 密集型任务的应用中,可以多配置一些线程。
(3)IO密集型和CPU密集型交叉运行 最佳线程数 =CPU 核数 * [ 1 +(I/O 耗时 / CPU 耗时)]
CPU 核数 * [ 1 +(I/O 耗时 / CPU 耗时)]
令 N=I/O 耗时 / CPU 耗时,当一个线程 执行 IO 操作时,另外 N个线程正好执行完各自的 CPU 计算,这样 CPU 的利用率就达到了 100%。