- 1.为什么要使用线程池
- 2.线程池相关类继承结构
- 3.ThreadPoolExecutor实现
- 3.1submit和execute方法实现
- 3.2execute代码执行流程
- 3.3Worker类
- 4.shutdown和shutdownNow的区别
1.为什么要使用线程池
- 3.1submit和execute方法实现
- 3.2execute代码执行流程
- 3.3Worker类
假如没有线程池,当存在较多的并发任务的时候,每执行一次任务,系统就要创建一个线程,任务完成后进行销毁,一旦并发任务过多,频繁的创建和销毁线程将会大大降低系统的效率。线程池能够对线程进行统一的分配,通过固定数量的线程来负责处理任务,避免了频繁的创建和销毁对象,使线程能够重复的利用,执行多个任务。
2.线程池相关类继承结构
Executor 最顶层接口,仅有execute方法。真正的线程池接口应该是它的子接口ExecutorService
ExecutorService接口,主要对Executor接口补充了一些方法,例如shutdown()、submit()等方法
ThreadPoolExecutor ExecutorService的默认实现,作为自定义线程池的主要类。
ScheduledExecutorService 用来解决任务重复执行的问题
ScheduledThreadPoolExecutor 继承ThreadPoolExecutor的ScheduledExecutorService接口实现,周期性任务调度的类实现。
3.ThreadPoolExecutor实现
corePoolSize
线程池中保存的线程个数,包含了空闲线程
maximumPoolSize
为线程池中最多允许线程个数
keepAliveTime
当线程产生的数量多于core时候,空闲线程在这个时间如果没有新任务将被终止
unit
keepAliveTime的时间单位,可直接使用TimeUnit枚举类
workQueue
线程工作任务队列。任务被执行前保存至工作队列 常用的有ArrayBlockingQueue、linkedBlockingQuene、priorityBlockingQuene等等
threadFactory
执行程序创建新线程时使用的工厂,默认为DefaultThreadFactory
handler
由于超出线程范围和队列容量而使执行被阻塞时所使用的处理程序,主要有四种AbortPolicy、CallerRunsPolicy、DiscardOldestPolicy、DiscardPolicy
3.1submit和execute方法实现
submit和execute都可以向线程池提交任务,不同的是,submit可以拿到执行的结果,execute则不行。
submit方法
execute方法
从源码中可以看出submit底层调用的也是execute,只不过是对结果进行了封装,核心逻辑还是在execute方法里,因此我们以分析execute为重点。
3.2execute代码执行流程
3.3addWorker方法
Expand source
3.3Worker类
从源码中可以看出Worker继承了AbstractQueuedSynchronizer,实现了独占非重入锁的功能,Worker有两个重要的属性,一个是thread工作线程,一个是firstTask待执行的任务。
Worker类里面的核心方法是runWorker,具体代码如下
接下来看getTask()方法
图中标红的两个部分结合在一起,实现了,线程池的这个特性,当线程产生的数量多于core时候,空闲线程在这个时间如果没有新任务将被终止。
4.shutdown和shutdownNow的区别
shutdown源码
shutdownNow
从源码中可以看出来,shutdown和shutdownNow的主要区别在interruptIdleWorkers和interruptWorkers这两个方法上。接下来看这两个方法的实现。
interruptIdleWorkers源码如下
interruptWorkers源码如下
可以看到interruptWorkers方法最终调用了Worker类的interruptIfStarted方法,interruptIfStarted方法如下
从源码中可以看出,shutdown在关闭线程池的时候会调用资源的tryLock方法尝试获取锁,在线程还有任务执行的时候,tryLock获取锁失败,在线程执行完释放锁之后,tryLock就可以获取锁成功,从而达到,只有在线程执行完任务之后才关闭线程池的目的。而shutdowNow则不关心是否可以获取锁,只要线程状态正确,就会打断线程的执行,关闭线程。



