当前位置 博文首页 > 立志欲坚不欲锐,成功在久不在速度:并发编程-ThreadPoolExecuto
目录
前言:
FixedThreadPool
参数:
执行流程图:
?代码测试:
执行流程
不推荐使用该方式来创建线程池:
SingleThreadExecutor
参数:
流程图:
CachedThreadPool
SynchronousQueue队列的特点:
执行流程图:
项目中用了这个Cahce线程池出现的问题:
Executors 返回线程池对象的弊端如下:
上一篇介绍的是直接使用ThreadPoolExecutor来创建线程池,很多人也称通过ThreadPoolExecutor创建线程池为自定义线程池
Executor其实还提供了三种类型的线程池:
先来看一下FixThreadPool的构造函数:?
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(),
threadFactory);
}
会发现底层其实用的就是ThreadPoolEexcutor来实现的,只不过是参数已经写死了
核心线程数: nThreads 外面传递进来
最大线程数: 等于核心线程数
时间: 0
时间单位: 毫秒
队列: new LinkedBlockingQueue<Runnable> 无限大
public LinkedBlockingQueue() {
this(Integer.MAX_VALUE);
}
?
我们从参数上可以发现它的核心线程数就等于最大线程数
LinkedBlockingQueue
;LinkedBlockingQueue
中获取任务来执行; 通过take拿????????由于核心线程数就等于最大线程数,并且阻塞队列是无限增大的,所以当任务过来的时候他会无限的排队所以不推荐使用这种方式,因为会造成OOM。
????????使用无界队列?LinkedBlockingQueue
?作为线程池的工作队列(队列的容量为 Intger.MAX_VALUE)。无界队列作为线程池的工作队列会对线程池带来不好的影响,说简单点就是可能会导致 OOM,队列的本质是数据结构,就是用来存储的,所以队列满了才会出现内存溢出
SingleThreadExecutor
?是只有一个线程的线程池。下面看看SingleThreadExecutor 的实现:
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
核心线程数:1
最大线程数:1
线程队列: 和fixed的一样都是无限大
?
LinkedBlockingQueue
LinkedBlockingQueue
中获取任务来执行;????????同样也不推荐使用sing线程池,因为他和fix线程池一样都是使用无界队列作为线程池队列,所以会造成OOM,sing线程池适合的业务场景就是需要按照顺序来依次执行,但是效率会很低
是一个会根据需要不断创建新线程的线程池
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(),
threadFactory);
}
?????????CacheThreadPool的corePoolSize被设置为0,但是maximumPoolSize被设置为最大值,几乎是无界的,也就意味着如果主线程提交任务的速度高于线程处理任务的速度,CachedThreadPool就会不断的创建新的任务,但是这个线程池的阻塞队列用的是SynchronousQueue
队列中同时只有一个节点,只能装一个数据,只有当前的数据被消费了才能继续装新的数据 (一夫一妻制)传球手,这个特点不会导致Cache线程池先出OOM,但是由于它的最大线程数为无限大会出现CPU爆满的问题
????????从图上我们可以发现,几乎所有的任务都创建线程了,因为maximumPoolSize是无界的,所以提交任务的速度 > 线程池中线程处理任务的速度就要不断创建新线程;每次提交任务,都会立即有线程去处理,因此CachedThreadPool适用于处理大量、耗时少的任务
?所以还是要谨慎消息使用这个线程,在项目中我们在汇总成绩部分用到了线程池,但是由于同事使用了这个Cache线程池来执行了批量导出的任务,导致任务多的时候CPU打满了,后来通过线上排查发现所有的线程都在执行这个任务,导致其他工作无法正常进行,后来将这部分优化为使用threadPoolExecutor来执行线程任务,性能提升了很多,不会出现CPU打满的情况
FixedThreadPool
?和?SingleThreadExecutor
?: 允许请求的队列长度为 Integer.MAX_VALUE,可能堆积大量的请求,从而导致 OOM。