《八:Java 并发包中线程池ThreadPoolExecutor原理》
线程池主要解决两个问题:
1. |
一是当执行大量异步任务时线程池能够提供较好的性能。在不使用线程池时,每当需要执行异步任务时直接new 一个线程来运行,而线程的创建和销毁是需要开销的。线程池里面的线程是可复用的,不需要每次执行异步任务时都重新创建和销毁线程。 |
2. |
二是线程池体提供了一种资源限制和管理的手段,比如可以限制线程的个数,动态新增线程等。每个ThreadPoolExecutor 也保留了一些基本的统计数据,比如当前线程池完成的任务数目等。 |
总结: |
线程池也提供了许多可调用参数和可扩展性接口,以满足不同情景的需要,程序员可以更方便的Executors的工厂方法,比如newCachedThreadPool(线程池线程个数最多可达Integer.Max_value,线程自动回收),newFixedThreadPool(固定大小的线程池),newSingleThreadExecutor(单个线程)等来创建线程池。 |
线程池状态如下:
running: |
接受新任务并且处理阻塞队列里的任务 |
shutdown: |
拒绝新任务但是处理阻塞队列里的任务 |
stop: |
拒绝新任务并且抛弃阻塞队列里的任务,同时会中断正在处理的任务。 |
tidying: |
所有任务都执行完毕后当前线程池活动线程数为0,将要调用terminated方法。 |
terminated: |
终止状态,terminated 方法调用完毕以后的状态。 |
线程池状态转换过程:
running->shutdown: |
显式调用shutdown方法,或者隐式调用了finalize()方法里面的shutdown()方法 |
running|shutdown ->stop : |
显式调用shutdownNow()方法。 |
shutdown->tidying: |
当线程池和任务队列都为空时。 |
stop->tidying: |
当线程池为空时。 |
tidying->terminated: |
当terminated()hook方法执行完成时。 |
线程池中的参数
corePoolSize: |
线程池核心线程个数 |
workQueue: |
用于保存等待执行的任务的阻塞队列,比如基于数组的有界ArrayBlockingQueue,基于链表的无界LinkedBlockingQueue,最多只有一个元素的同步队列SynchronousQueue以及优先队列PriorityBlockingQueue等。 |
maximunPoolSize: |
线程池最大线程数量 |
ThreadFactory: |
创建线程的工厂。 |
RejectedExecutionHandler: |
饱和策略。当队列满并且线程个数达到线程池最大线程数量后采取的策略,比如AbortPolicy(抛出异常),CallerRunsPolicy(使用调用者所在线程来运行任务),DiscardOldestPolicy(调用poll丢弃一个任务,执行当前任务),以及DiscardPolicy(默默丢弃,不抛出异常)。 |
keeyAliveTime: |
存活时间。如果当前线程池中的线程数量比核心线程数量多,并且是闲置状态,则这些闲置的线程能存活的最大时间。 |
TimeUnit: |
存活时间的时间单位。 |
Java通过Executors提供四种线程池,分别为:
newCachedThreadPool |
创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。 |
newFixedThreadPool |
创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。 |
newScheduledThreadPool |
创建一个定时性线程池,支持定时及周期性任务执行。 |
newSingleThreadExecutor |
创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。 |
Executors 是个工具类,里面提供了好多静态方法,这些方法根据用户选择返回不同的线程池实例。ScheduledThreadPoolExecutor继承了ThreadPoolExecutor并实现了ScheduledExecutorService接口,线程池队列是DelayedWorkQueue,是一个延迟队列。ScheduledFutureTask是具有返回值的任务,继承自FutureTask。FutureTask的内部有一个变量state用来表示任务的状态,一开始状态为NEW。
线程池中的方法
execute方法: |
execute方法的作用是提交任务command到线程池进行执行。 |
worker |
用户线程提交任务到线程池后,由worker来执行。 |
shutdown方法: |
调用shutdown方法后,线程池就不会再接受新的任务了,但是工作队列里面的任务还是要执行的。该方法会立刻返回,并不等待队列任务完成再返回。 |
shutdownNow方法: |
调用shutdownNow方法后,线程池就不会再接受新的任务了,并且会丢弃工作队列里面的任务,正在执行的任务会被中断,该方法会立刻返回,并不等待激活的任务执行完成。返回值为这时候队列里面被丢弃的任务列表。 |
awitTermination方法: |
当线程调用awitTermination方法后,当前线程会被阻塞,直到线程池状态变成terminated才返回,或者等待时间超时才返回。 |
总结: |
线程池巧妙的使用一个Integer类型的原子变量来记录线程池的状态和线程个数。通过线程池状态来控制任务的执行,每个worker线程可以处理多个任务。线程池通过线程的复用减少了线程创建和销毁的开销。 |