线程池的实现原理
runState 线程池的运行状态
running:表明线程池在运行当中,可以接受新的任务,也可以处理阻塞队列中的任务。
shutdown:不可以接受新的任务了,但是还可以执行阻塞队列中的任务。
stop:不可接收新任务,不可执行阻塞队列里的任务了,并且尝试终止所有在运行任务。
tidying:所有任务已经终止,执行terminated()
terminated:线程池完全关闭
在ThreadPoolExecutor的构造方法中,定义了线程池的核心线程数,最大线程数,过期时间,时间单位,阻塞队列,创建线程的工厂,拒绝策略。下面来看看默认的线程工厂,它到底是如何创建新的线程的。
DefaultThreadFactory实现了ThreadFactory接口,
在DefaultThreadFactory构造方法中确定线程的命名前缀,之后每创建一个线程,poolNumber不变,threadNumber++,并设置线程是否是Deamon线程、线程的优先级等。
何时调用newThread()方法呢?Worker是对提交任务的封装,如果调用Worker的构造方法,就会创建一个新的线程中去执行任务。
||左边为真,右边就不再执行了,也就是如果task不为null,就运行firstTask,如果为null,就从阻塞队列获取任务执行。
while (task != null || (task = getTask()) != null)
现在我们来看看线程池的运行原理:当提交任务到线程池中,会调用execute方法
如果当前线程数比核心线程数小,那么就添加一个Worker(也就是创建一个新的线程,去处理这个任务),并直接return。如果已经达到核心线程数,那么新来的任务会插入到阻塞队列中,也就是workQueue.offer(command).如果队列也满了,还有任务到来的话,那么就继续创建新的线程。如果创建新的线程时池子已经达到最大线程数,就采取拒绝策略。
添加Worker的方法:
在该方法中会调用new Worker(firstTask)构造函数,创建线程并运行此任务。
如何关闭线程池呢?
shutdown()方法会停止接受任务,但是已经提交的任务可以继续执行。该方面将线程池状态改为shutdown,然后中断所有空闲的线程。
在中断所有空闲线程的方法中,有一个tryLock(),如果线程正在执行,是持有锁的,所以tryLock()获取不到,也就不会中断了。
shutdownNow()方法将线程池状态设置成stop,不能再提交任务,已经提交但未执行的任务不能运行,正在运行的任务可继续运行,但会被中断(尝试终止所有在运行任务),返回已经提交但未执行的任务。
这里会中断所有的线程
最后都要调用tryTerminate()方法,尝试彻底关闭线程池,会先用CAS将线程池状态改为tidying,最后调用terminated()方法。