Concurrency-线程池
在并发过程中,合理使用线程池带来3个好处:
- 降低资源消耗 通过重复利用已创建的线程降低线程创建和销毁的消耗。
- 提高响应速度 当任务到达时,任务可以不需要等线程创建就能立即执行。
- 提高线程的可管理性 使用线程池可以对线程进行统一分配、调优和管控。
线程池实现原理
当提交一个新任务到线程池时,线程池的处理流程:

- 线程池判断
核心线程池
里的线程是否都在执行任务。如果不是,创建一个新的工作线程来执行任务;如果不是,进入下一流程。 - 线程池判断工作队列是否已满。如果不满,则将新任务放到工作队列中;如果满了,进入下一流程。
- 线程池判断
线程池
是否都处于工作状态。如果不是,创建一个新的工作线程来执行任务;如果不是,执行饱和策略。
ThreadPoolExecutor执行过程

ThreadPoolExecutor执行execute方法分下面4种情况:
- 如果当前运行的线程少于corePoolSize,则创建新线程来执行任务(执行这一步骤需要获取全局锁)。
- 如果运行的线程等于或多于corePoolSize,则将任务加入BlockingQueue。
- 如果无法将任务加入BlockingQueue(队列已满),则创建新的线程来处理任务(执行这一步骤需要获取全局锁)。
- 如果创建新线程将使当前运行的线程超出maximumPoolSize,任务将被拒绝,并调用RejectedExecutionHandler.rejectedExecution()方法。
ThreadPoolExecutor执行任务:
线程池创建线程时,会将线程封装成工作线程worker,worker执行完任务后会循环
从工作队列中获取任务来执行。
(此处应有图)
ThreadPoolExecutor创建
public ThreadPoolExecutor(
int corePoolSize, // 核心线程数,初始化的线程数
int maximumPoolSize, // 最大线程数
long keepAliveTime, // 空闲线程最大存活时间
TimeUnit unit, // 单位
BlockingQueue<Runnable> workQueue, // 任务队列
ThreadFactory threadFactory, // 用于设置创建线程的工厂
RejectedExecutionHandler handler // 拒绝任务时的操作(拒绝策略)
)
corePoolSize
线程池核心线程数大小。
IO密集型:
CPU密集型:
runnableTaskQueue 任务队列
用于保存等待执行的任务的阻塞队列:
- ArrayBlockingQueue 基于数组结构的有界阻塞队列
- LinkedBlockingQueue 基于链表结构的阻塞队列,吞吐量通常高于ArrayBlockingQueue
- SynchronizedQueue 一个不存储元素的阻塞队列,插入操作会被阻塞直到元素被移除,吞吐量通常高于LinkedBlockingQueue
- PriorityBlockingQueue 一个具有优先级的无界阻塞队列
maximumPoolSize
线程池最大数量。如果使用了无界队列这个参数就没有效果。
ThreadFactory
用于设置创建线程的工厂,使用guava提供的ThreadFactoryBuilder可以快速给线程设置有意义的名字:
new ThreadFactoryBuilder().setNameFormat("XX-task-%d").build();
RejectedExecutionHandler
饱和策略。当队列和线程池都满了,需要采取一种饱和策略来处理新提交的任务:
- AbortPolicy 直接抛出异常。默认策略。
- CallerRunsPolicy 调用者所在线程来运行任务。
- DiscardOldestPolicy 丢弃队列里最近的一个任务,并执行当前任务。
- DiscardPolicy 不处理任务,直接丢弃。
也可以实现RejectedExecutionHandler接口自定义策略。比如记录日志或持久化存储不能处理的任务。
keepAliveTime
TimeUnit
向线程池提交任务
execute
没有返回值
submit
有返回值。通过返回future对象的get()获取线程的执行结果。get()会一直阻塞直到任务完成。
线程池监控
通过扩展线程池进行监控。继承线程池重写beforeExecute、afterExecute、terminated方法来实现监控。
一般监控使用的属性:
- taskCount 线程池需要执行的任务数量
- completedTaskCount 线程池在运行过程中已完成的任务数量,小于或等于taskCount
- largePoolSize 线程池里曾经创建过的最大线程数量。如果等于线程池的最大大小,说明线程池满过。
- getPoolSize 线程池的线程数量。
- getActiveCount 获取活动的线程数。
ExecutorService
ExecutorService是Java中对线程池的一种实现。ExecutorService接口的实现类有两个:
- ThreadPoolExecutor
- ScheduledExecutorService
ExecutorService创建
ExecutorService可以通过Executors框架快速创建4种线程池:
- newFixedThreadPool 创建一个固定长度的线程池,每提交一个任务就创建一个线程,直到达到线程池的最大数量,这时线程池的规模不再变化;默认使用无界队列LinkedBlockingQueue。
- newCachedThreadPool 创建一个可缓存的线程池,如果线程池的当前规模超过了处理请求时,线程池将会回收空闲线程,而当需求增加时,可以添加新的线程,线程池规模不受限制;默认使用SynchronizedQueue。
- newScheduledThreadPool
- newSingleThreadPool
ExecutorService关闭
- shutdown 执行shutdown之后不会立即关闭线程池,但是不会再接收新任务,直到线程池所有任务都执行完毕才会关闭,在调用之前提交的任务都会被执行。
- shutdownNow 线程池不接受新任务,但不对已经执行的任务做限制。
网友评论