java线程池知识要点笔记
使用线程池的优点:
降低资源消耗:重复使用已创建的thread
提高系统响应速度:线程池预热后,任务提交不需要等待线程创建就能执行
提高线程的可管理性:线程池可以进行统一分配,调优,管理
执行流程
再提交任务之后,首先检查核心线程池(corePool)是否处于饱和状态(核心线程数量是否达到最大、核心线程是否存在空闲)
假如不饱和则创建新的线程执行
假如饱和则进入下一流程:把任务提交到任务队列(BlockingQueue)中
提交到任务队列之前首先判断,队列是否饱和
假如任务队列不饱和,则任务入列
假如任务队列饱和则进入下一流程:任务线程池
首先线程池判断线程池(maximunPool)的线程是否饱和
假如不饱和则,创建新的线程执行
假如饱和则交给饱和策略(RejectedExecutionHandler)来处理这个任务
常用框架&工具:Executor框架&Executors工具
Executor 核心类:ThreadPoolExecutor、ScheduledThreadPoolExecutor、Future、Runnable、Callable
继承关系
常用的三种TheadPoolExecutor
FixedThreadPool,SingleThreadExecutor,CachedThreadPool
对应了三种初始化TheadPoolExetuor的方法,从而有了不同的特性。下面看看Executors工具源码中的初始化这三种TheadPoolExecutor的方法。
FixedThreadPool:
public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); }
从该方法可以看出ThreadPoolExecutor的特点
corePoolSize 和 maximumPoolSize大小同为nThreads,线程空闲(KeepAliveTime)时间设置为0,这意味着当线程池中的线程数量大于corePoolSize时,多余的空闲线程会被立即销毁。更重要的是使用了LinkedBlockingQueued无界队列(队列容量是Integer.MAX_VALUE)通过上述的线程池的工作流程可以知道,无界队列意味着。当corePool中的线程饱和后所有的任务都会提交到任务队列进行等待。
使用无界队列,那么参数maximumPoolSize 无效,keepAliveTime参数无效,而且没有执行shutdown或者shutdowmNow方法的线程池不会触发饱和处理机制。(原因详见上述的线程池的工作流程)
SingleThreadExecutor:
public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())); }
从源码可以看出和FixThreadPool大同小异,只是SingleThreadExecutor只有一个核心线程
CachedThreadPool:
public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); }
见码知意:corePoolSize = 0;maximumPoolSize = Inteter.MAX_VALUE(线程数量无界),keepAliveTime = 60s
任务队列使用了SynchronousQueued队列(一个没有容量的对列,特点是每个插入操作必须先移除)
这些参数意味着,任务提交速度大于线程任务处理速度则 线程池会不断创建新的线程。