Java 线程池解析

线程池作用

  • 利用线程池管理并复用线程、控制最大并发数等
  • 实现任务线程队列缓存策略和拒绝机制
  • 实现某些与时间相关的功能,如定时执行、周期执行等
  • 隔离线程环境,比如,交易服务和搜索服务在同一台服务器上,分别开启两个线程池,交易线程的资源消耗明显要大;因此,通过配置独立的线程池,将较慢的交易服务与搜索服务隔离开,避免各服务线程相互影响.

线程池好处

  • 降低资源消耗: 通过重复利用已创建的线程,降低创建和销毁线程造成的系统资源消耗
  • 提高响应速度: 当任务到达时,任务可以不需要等到线程创建就能立即执行
  • 提高线程的可管理性: 线程是稀缺资源,如果过多地创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一分配、调优和监控。

线程池构造解析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
if (corePoolSize < 0 ||
maximumPoolSize <= 0 ||
maximumPoolSize < corePoolSize ||
keepAliveTime < 0)
throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}

七个参数解析:

1. corePoolSize
线程池中的常驻核心线程数,一般不会被回收。
如果 executor.allowCoreThreadTimeOut(true) ,那么核心线程如果不干活(闲置状态)的话,超过一定时间( keepAliveTime),就会被销毁掉

2. maximumPoolSize
线程池能容纳同时执行的最大线程数,线程总数计算公式 = 核心线程数 + 非核心线程数。

3. keepAliveTime
非核心空闲线程的存活时间。

4. TimeUnit
keepAliveTime 的时间单位。

5. workQueue
任务队列,存放被提交但尚未执行的任务。

6. threadFactory
生成线程池中工作线程的线程工厂。

7. handler
拒绝策略。

  • hreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
  • ThreadPoolExecutor.DiscardPolicy:丢弃任务,但是不抛出异常。
  • ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列等待最久的任务,然后重新尝试执行任务(重复此过程)
  • ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务

JDK 自带的线程池

1
2
3
4
5
6
// 单线程
Executor executor1 = Executors.newSingleThreadExecutor();
// 固定长度
Executor executor2 = Executors.newFixedThreadPool(5);
// 可扩展,随需创建线程数
Executor executor3 = Executors.newCachedThreadPool();

一般不会直接使用以上三种,而是手写 ThreadPoolExecutor 实现线程池,因为阻塞队列的最大值为 Integer.MAX_VALUE ,会造成OOM。

合理配置线程池

1. cpu 密集型:(需要大量运算,不会阻塞,宜少配置线程数)

cpu核心数+1

2. IO 密集型:(需要大量IO,会阻塞,宜多配置线程数)

cpu核心数*2

0%