浅谈线程池及 Executors 框架
线程池是什么
线程池(Thread Pool)是一种线程使用模式。线程池维护着多个线程,等待调用者分配需要并发执行的任务。这避免了在处理耗时短的任务时创建与销毁线程的开销。线程池不仅能保证内核的充分利用,还能防止过分调度。线程池一般设置为 CPU 数 +2 比较合适,线程过多会带来额外的调度开销。
线程池带来的好处
- 重复利用线程,减少线程创建、销毁的开销,提高性能
- 控制并发线程数,避免短时间创建大量线程导致系统资源耗尽和过度调度
- 提供了定时、定期执行功能
- 批量管理线程
线程池的潜在影响
- 创建太多线程,将会浪费一定的资源,部分线程未被充分利用
- 销毁太多线程,将导致之后浪费时间再次创建
- 创建线程太慢,将会导致长时间等待,性能变差
线程池使用场景
- 需要大量线程,且单个任务执行时间短
- 对性能要求高,如完成快速响应
- 接受突发的大量请求
线程池的创建方式
使用 Executors 框架创建
java.util.concurrent.Executors
是 JDK 默认提供的快速创建线程池的类,主要有以下 4 种方式
newSingleThreadExecutor
下面是源码
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
创建一个单线程的线程池,它使用一个工作线程在无界队列中运行。如果这个单线程在关闭之前由于执行失败而终止,并且需要去处理后续任务,将会产生一个新线程取代它。
单线程的线程池保证任务按顺序执行,并且保证在任何时间只有一个线程处于活动状态。
newFixedThreadPool
下面是源码
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
创建一个固定大小的线程池,该线程池重用固定数量的线程在共享的无界队列中运行。在任何时候,最多有 nThreads 个线程活动。如果在所有线程都处于活动状态时提交了新任务,将被放在队列中等待,直到有空闲线程可用。如果任何一个线程在关闭前的执行过程中因失败而终止,在后续需要执行任务时,将会产生一个新线程取代它。池中的线程将一直存在,直到线程池被明确的 shutdown。
newCachedThreadPool
下面是源码
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
创建一个可缓存的线程池,将根据需要创建新线程,但在可用时优先重用之前的线程。如果没有可用的现有线程,将会新建一个线程并将其加入到池中。60s 内未使用的线程将被关闭,并且从缓存中删除。因此,保持空闲时间足够长的此类型线程池,将不会消耗任何资源。
newScheduledThreadPool
下面是源码
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
创建一个定时的线程池,可以安排任务在给定的延迟后运行,或定期执行。
如果上述的创建方式无法满足你的需求,还可以通过自定义线程参数的方式创建。Executors 也是通过调用 ThreadPoolExecutor 来创建的。
使用 ThreadPoolExecutor 自定义线程池
这种创建方式提供了以下 7 个参数供用户配置
corePoolSize
核心线程数,要保留在池中的线程数,即使它们处于空闲状态
maximumPoolSize
池中允许的最大线程数
keepAliveTime
当活动线程数大于核心线程数时,在多余空闲线程被终止前等待新任务的最大时间
TimeUnit
keepAliveTime 参数的时间单位
workQueue
在执行任务之前保存任务的队列
ThreadFactory
创建新线程的工厂
RejectedExecutionHandler
在达到线程数边界和队列容量时,对新任务的拒绝策略
作者:超级鲨鱼辣椒
转载请注明原文链接:https://www.cnblogs.com/jinzlblog/p/15168648.html