一.什么是线程池?
线程池顾名思义就是事先创建若干个可执行的线程放入一个池(容器)中,需要的时候从池中获取线程不用自行创建。使用完毕后不需要销毁线程而是放回池中,从而减少创建和销毁线程对象的开销。
二.线程池的工作原理
当提交一个任务时,首先判断线程池中核心线程池所有的线程是否都在执行任务。如果不是,则新创建一个线程执行刚提交的任务,否则,核心线程池中所有的线程都在执行任务,则进入第2步;
判断当前阻塞队列是否已满,如果未满,则将提交的任务放置在阻塞队列中;否则,则进入第3步;
判断线程池中所有的线程是否都在执行任务,如果没有,则创建一个新的线程来执行任务,否则,则交给饱和策略进行处理。
三. 线程池的创建实现
创建线程池主要是ThreadPoolExecutor类来完成,ThreadPoolExecutor的有很多重载的构造方法,通过参数最多的构造方法来理解创建线程池有哪些需要配置的参数。ThreadPoolExecutor的构造方法为:
ThreadPoolExecutor(corePoolSize,maxPoolSize,keepAliveTime,timeUnit,workQueue,
threadFactory,handle);
corePoolSize 线程池中的核心线程数,当提交一个任务时,线程池创建一个新线程执行任务,直到当前线程数等于 corePoolSize;所创建的核心线程即使在没有用的时候也不会被回收,如果当前线程数为corePoolSize,继续提交的任务被保存到阻塞队列中,等待被执行; 如果调用了prestartCoreThread()或者 prestartAllCoreThreads(),线程池创建的时候所有的核心线程都会被创建并且启动。
maximumPoolSize 线程池中允许的最大线程数。如果当前阻塞队列满了,且继续提交任务,则创建新的线程执行任务, 前提是当前线程数小于maximumPoolSize;
keepAliveTime 就是线程池中除了核心线程之外的其他的最长可以保留的时间,因为在线程池中,除了核心线程即使在无任务的情况下也不能被清除,其余的都是有存活时间的,意思就是非核心线程可以保留的最长的空闲时间;
unit 是计算keepAliveTime 的单位;
workQueue 用来保存等待被执行的任务的阻塞队列,且任务必须实现 Runable 接口,在 JDK 中提供了如下阻塞 队列:
1、ArrayBlockingQueue:基于数组结构的有界阻塞队列,按 FIFO(先进先出) 排序任务;
2、LinkedBlockingQuene:基于链表结构的阻塞队列,按 FIFO(先进先出) 排序任务,吞吐量通常要高于 Array BlockingQuene;
3、SynchronousQuene:一个不存储元素的阻塞队列,每个插入操作必须等到另一个线程调用移除 操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于 LinkedBlockingQuene;
4、priorityBlockingQuene:具有优先级的无界阻塞队列;
threadFactory 创建线程的工厂,通过自定义的线程工厂可以给每个新建的线程设置一个具有识别度的线程名。
5、handler 线程池的饱和策略,当阻塞队列满了,且没有空闲的工作线程,如果继续提交任务,必须采取一种策 略处理该任务,线程池提供了 4 种策略:
1、AbortPolicy:直接抛出异常,默认策略;
2、CallerRunsPolicy:用调用者所在的线程来执行任务;
3、DiscardOldestPolicy:丢弃阻塞队列中靠最前的任务,并执行当前任务; 4、DiscardPolicy:直接丢弃任务; 当然也可以根据应用场景实现 RejectedExecutionHandler 接口,自定义饱和策略,如记录日志或持 久化存储不能处理的任务。
四.线程池的分类:
4 种类型的线程池:
newFixedThreadPool() 说明:初始化一个指定线程数的线程池,其中 corePoolSize == maxiPoolSize,使用 LinkedBlockin gQuene 作为阻塞队列 特点:即使当线程池没有可执行任务时,也不会释放线程。
newCachedThreadPool() 说明:初始化一个可以缓存线程的线程池,默认缓存 60s,线程池的线程数可达到 Integer.MAX_VA LUE,即 2147483647,内部使用 SynchronousQueue 作为阻塞队列; 特点:在没有任务执行时,当线程的空闲时间超过 keepAliveTime,会自动释放线程资源;当提交新 任务时,如果没有空闲线程,则创建新线程执行任务,会导致一定的系统开销; 因此,使用时要注意控制并发的任务数,防止因创建大量的线程导致而降低性能。 newSingleThreadExecutor() 说明:初始化只有一个线程的线程池,内部使用 LinkedBlockingQueue 作为阻塞队列。 特点:如果该线程异常结束,会重新创建一个新的线程继续执行任务,唯一的线程可以保证所提交任 务的顺序执行 newScheduledThreadPool() 特定:初始化的线程池可以在指定的时间内周期性的执行所提交的任务,在实际的业务场景中可以使 用该线程池定期的同步数据。
总结:除了 newScheduledThreadPool 的内部实现特殊一点之外,其它线程池内部都是基于 Thread PoolExecutor类(Executor 的子类)实现的。
五.线程池状态
RUNNING 自然是运行状态,指可以接受任务执行队列里的任务
SHUTDOWN 指调用了 shutdown() 方法,不再接受新任务了,但是队列里的任务得执行完毕。
STOP 指调用了 shutdownNow() 方法,不再接受新任务,同时抛弃阻塞队列里的所有任务并中断所 有正在执行任务。
TIDYING 所有任务都执行完毕,在调用 shutdown()/shutdownNow() 中都会尝试更新为这个状态。
TERMINATED 终止状态,当执行 terminated() 后会更新为这个状态