线程池
1.ThreadPoolExecutor
1.线程池参数
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
corePoolSize:核心线程数
maximumPoolSize:maximumPoolSize – the maximum number of threads to allow in the pool
非核心线程数=maximumPoolSize - 核心线程数
keepAliveTime: 时间
unit :时间单位 非核心线程会有存活时间,到时间会自动销毁,比如有定时任务删除未支付订单,大促时会增加非核心线程处理未处理订单
workQueue:队列 处理任务太多排队,线程处理完从队列里取任务
threadFactory:线程工厂,线程从线程工厂创建
handler:拒绝策略,队列排满了就会拒绝掉
newCachedThreadPool
会让CPU100%,因为最多创建线程Integer.MAX_VALUE (0x7fffffff) 2的31次方-1
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
newFixedThreadPool
每次最多固定线程执行,任务放到队列中,可能会内存溢出
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
newSingleThreadExecutor
任务放到队列中,可能会内存溢出
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
2.线程池执行流程
线程优先级
提交优先级:
- 先提交核心线程
- 再提交等待队列
- 最后提交非核心线程
执行优先级:先执行已经有的任务,最后执行等待队列里的任务
- 先执行核心线程任务
- 再执行非核心线程任务
- 最后执行队列里的任务
ThreadPoolExecutor.java源码1127行
while (task != null || (task = getTask()) != null) {
getTask()是从队列里取
拒绝策略场景分析
(1)AbortPolicy
AbortPolicy
ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
这是线程池默认的拒绝策略,在任务不能再提交的时候,抛出异常,及时反馈程序运行状态。如果是比较关键的业务,推荐使用此拒绝策略,这样子在系统不能承载更大的并发量的时候,能够及时的通过异常发现。
(2)DiscardPolicy
ThreadPoolExecutor.DiscardPolicy:丢弃任务,但是不抛出异常。如果线程队列已满,则后续提交的任务都会被丢弃,且是静默丢弃。
使用此策略,可能会使我们无法发现系统的异常状态。建议是一些无关紧要的业务采用此策略。例如,本人的博客网站统计阅读量就是采用的这种拒绝策略。
(3)DiscardOldestPolicy
ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新提交被拒绝的任务。
此拒绝策略,是一种喜新厌旧的拒绝策略。是否要采用此种拒绝策略,还得根据实际业务是否允许丢弃老任务来认真衡量。
(4)CallerRunsPolicy
ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务
如果任务被拒绝了,则由调用线程(提交任务的线程)直接执行此任务,我们可以通过代码来验证这一点:
public static class CallerRunsPolicy implements RejectedExecutionHandler {
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
r.run();
}
}
}
如果线程池已经被关闭,则直接丢弃该任务。r.run()(.run只是普通调方法) 是调用者所在线程来运行任务。
(5)通过实现 RejectedExecutionHandler 接口自定义拒绝策略
关注公账号获取插件地址