线程池介绍
1、常用线程池
官方建议使用Executors工厂方法提供的线程池。newFixedThreadPool、newSingleThreadExecutor、newCachedThreadPool、newSingleThreadScheduledExecutor、newScheduledThreadPool。以上线程池覆盖大部分场景,如果因业务需求,需详细配置可以继续阅读,了解线程池的使用方法和原理。
2、初始化参数
ThreadPoolExecutor四个构造函数由以下不同参数去实例化,需要特殊配置线程池需要使用以下七个参数。以下是参数介绍及使用介绍。
corePoolSize:核心线程数。线程池保有线程数量(即使线程是闲置的),如果设置allowCoreThreadTimeOut=true(默认false),闲置线程等待指定存活时间,若无任务,则终止。默认情况下线程池初始化后线程数量=0,只有新任务提交时才会创建线程。
当然线程池也提供了另外三个创建线程的方式:prestartCoreThread(创建一个核心闲置线程等待新任务,如果所有核心线程已经被创建,方法返回false)、ensurePrestart(同prestartCoreThread,特殊处是核心线程数=0时,仍保证创建至少一个线程)、prestartAllCoreThreads(创建所有的核心限制线程),三个方法都覆盖了默认有新任务时创建线程的策略。当任务队列不为空时,则可以使用三种策略预先启动新线程。
maxMumPoolSize:最大线程数。线程池允许的最大线程数量。可以设置为基本无界值(如Integer.MAX_VALUE),则将适应任意数量的并发任务,但也会带来很多弊端。
keepAliveTime:线程存活时间。线程数>corePoolSize,闲置线程在终止前等待新任务的时间。默认情况下,当线程数超过核心线程数,存活时间才会起作用,即只作用于非核心线程。等待新任务时间超过存活时间,线程则中止,直至线程数<corePoolSize。若线程池设置了allowCoreThreadTimeOut=true,线程等不到新任务,超过存活时间终止,直至线程数=0。
TimeUnit:存活时间单位。枚举类java.util.concurrent.TimeUtil提供纳秒~天
BlockingQueue:任务队列(阻塞)。线程任务(由execute提交的Runnable类型任务)被执行前存放在该阻塞队列。BlockingQueue目前的实现类如下(jdk 1.7),常用队列ArrayBlockIng、LinkedBlockingQueue。排队策略:无界队列(如LinkedBlockingQueue不初始化容量),有界队列(ArrayBlockIng),直接提交(默认选项是 SynchronousQueue
)。三种队列的特性将会影响线程池的初始配置和运行,将会在线程池配置详细说明。附:队列类的特性及相关知识,可查看容器类介绍。
ThreadFactory:线程工厂。创建新线程的工程。默认使用Executors.defaultThreadFactory创建线程,且线程优先级(NORM_PRIORITY )和非守护进程状态相同。自定义ThreadFactory可以改变线程优先级等。
RejectedExceptionHandler:线程池拒绝异常处理器。线程数量超过线程池承载,会报此异常,表示线程池拒绝处理。线程池拒绝新任务后的操作。默认线程池抛出RejectedExecutionException(Java线程池提供了四种异常策略,可见于线程池类注释)。可自定义,实现RejectedExecutionHandler接口,重写rejectedExecution方法即可。
3、其它特性
hook钩子
队列维护
中止
Executors提供的几类线程池初始化参数也是使用以上七个,只是场景不同,参数值不同。
4、原理
4.1 工作流程:
(1)通过ThreadPoolExecutor.execute提交任务,当小于corePoolSize时,即使有空闲的线程,仍会开启一个新线程,且任务不会进入队列排队。原子操作addWorker会检查runState和workerCount,无法添加时会报异常。
(2)当线程数大于核心线程数(workerCount>=corePoolSize),新任务会先添加到任务队列(BlookingQueue)排队等待。添加任务时仍然需要仔细核查线程池的状态(runState)以及当线程入队后状态不满足是否回滚入队任务。
(3)当任务无法入队,corePoolSize<线程数量<maxMumPoolSize会创建一个新线程,当大于最大线程数且队列已满,则会抛出异常,无法执行任务。
4.2 核心方法
(1)构造方法
ThreadPoolExecutor有四个构造方法,构造方法只是参数个数不同,按需构造。
(2)提交任务
5、线程池使用介绍
线程池提供的方法参考:http://tool.oschina.net/apidocs/apidoc?api=jdk-zh
怎么用-原理-注意事项