一、Executor概述
为更好控制线程,jdk提供一套线程管理框架Executor,帮助开发人员有效地进行线程控制。它们都位于java.util.concurrent包中,是jdk并发包的核心。其中有个比较重要的类:Executors,他扮演着线程工厂的角色,我们可以通过Executors创建特定功能的线程池。
二、Executors创建线程的方法
newFixedThreadPool()方法:返回一个固定数量的线程池,线程数始终不变,当有一个任务提交时,若线程池中空闲,则立即执行;若没有,则会被暂缓在一个任务队列里等待有空闲的线程去执行(队列是无界队列,无限缓存线程数)
newSingleThreadPoolExecutor()方法:创建一个线程的线程池,若空闲则执行,若没空闲线程则暂缓在任务队列(队列是无界队列,无限缓存线程数)
newCachedThreadPool():返回一个可根据实际情况调整线程个数的线程池,不限制最大线程数量,若有任务则创建线程执行,若无任务则不创建线程,并且每个空线程会在60s后自动回收。(初始化不创建线程)
newScheduledThreadPool():返回一个ScheduledExecutorService对象,但该线程池可以指定线程的数量(不限线程池数量),带有延迟时间的去获取线程。通常用spring的Scheduled
这4个方法返回的都是ThreadPoolExecutor对象
三、自定义线程池——ThreadPoolExecutor
若Executors的工厂方法无法满足我们的需求,可以自己用ThreadPoolExecutor去创建自定义的线程池(其实Executors的工厂方法内部就是用ThreadPoolExecutor类实现的)
(1)构造方法如下
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
corePoolSize:核心线程数
maximumPoolSize:最大线程数
keepAliveTime:每个线程保持活着的空闲时间数字
unit:keepAliveTime的时间单位
workQueue:存放线程的队列(线程超过maximumPoolSize时用到)
threadFactory:线程工厂,主要用来创建线程
handler:拒绝任务执行的处理器(情景:假设线程池数量最大为3,队列长度最大为2,现在有3个任务在执行未释放线程,而任务里也有2个任务在排队了,我们认为后面再来任务就可以丢弃了,这个handler处理的就是这种情况)
有以下四种取值:
ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。(JDK默认的拒绝策略)
ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。
ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
ThreadPoolExecutor.CallerRunsPolicy:只要线程池不关闭,该策略直接在调用者线程中,运行当前被丢弃的任务
个人认为这4中策略不友好,最好自己定义拒绝策略,实现RejectedExecutionHandler接口
构造方法详细解读:
a.构造方法的队列类型比较关键
如果使用有界队列
1).初始的poolSize < corePoolSize,提交的runnable任务,会直接做为new一个Thread的参数,立马执行 。
2).当提交的任务数超过了corePoolSize,会将当前的runable提交到一个block queue中。
3).有界队列满了之后,如果poolSize < maximumPoolsize(poolSize是在运行的线程数,不包括队列里面的线程)时,会尝试new 一个Thread的进行救急处理,立马执行对应的runnable任务。
4).如果3中也无法处理了(poolSize > maximumPoolsize),就会走到第四步执行reject操作。
如果使用无界队列,与有界队列相比,除非系统资源耗尽,否则无界的任务队列不存在任务入队失败的情况。当有新的任务到来,系统的线程数小于corePoolSize时,则新建线程执行任务。当达到corePoolSize后,就不会继续增加,若后续仍有新的任务加入,而没有空闲的线程资源,则任务直接进入队列等待。若任务创建和处理的速度差异很大,无界队列会保持快速增长,直到耗尽系统内存。(此时maximumPoolSize无意义)
四、ThreadPoolExecutor的submit与excute的区别
1.submit可以传入Callable接口的实例对象
2.submit方法有返回值