Java线程池有哪些状态?如何切换?java
线程池的种类有哪些?数组
建立线程池须要哪些参数?含义?缓存
将任务添加到线程池的运行流程?ide
线程池怎么重用线程?操作系统
线程池如何关闭?线程
来搞一下源码:ThreadPoolExecutor.javacode
private static final int RUNNING = -1 << COUNT_BITS; private static final int SHUTDOWN = 0 << COUNT_BITS; private static final int STOP = 1 << COUNT_BITS; private static final int TIDYING = 2 << COUNT_BITS; private static final int TERMINATED = 3 << COUNT_BITS;
各类状态的说明在源码的注释中都有,咱们来看一下:对象
The runState provides the main lifecycle control, taking on values:接口
RUNNING: Accept new tasks and process queued tasks SHUTDOWN: Don't accept new tasks, but process queued tasks STOP: Don't accept new tasks, don't process queued tasks,and interrupt in-progress tasks TIDYING: All tasks have terminated, workerCount is zero, the thread transitioning to state TIDYING will run the terminated() hook method TERMINATED: terminated() has completed
处于RUNNING状态的线程池能够接收新的任务,也可以处理阻塞队列里面的任务。队列
SHUTDOWN:不能接受新的任务,能够处理阻塞队列里面的任务。
STOP:不能接受新的任务,也不会处理阻塞队列的任务。并且中断正在处理的任务。
TIDYING:全部的任务都被终止,线程池中工做线程的数量为0,将要调用terminated()方法。
TERMINATED: terminated()方法调用完毕,终止状态。
状态之间进行切换:
RUNNING -> SHUTDOWN On invocation of shutdown(), perhaps implicitly in finalize() (RUNNING or SHUTDOWN) -> STOP On invocation of shutdownNow() SHUTDOWN -> TIDYING When both queue and pool are empty STOP -> TIDYING When pool is empty TIDYING -> TERMINATED When the terminated() hook method has completed
RUNNING切换到SHUTDOWN状态:调用shutdown()方法后切换到SHUTDOWN状态。
RUNNING、SHUTDOWN切换到STOP状态:调用shutdownNow()方法切换到STOP状态
SHUTDOWN切换到TIDYING状态:在阻塞队列和线程池为空的状况下切换到TIDYING状态。
STOP切换到TIDYING状态:线程池为空时切换到该状态。
TIDYING切换到TERMINATED状态: 调用terminated()方法切换到该状态。
源码中建立ThreadPoolExecutor的构造方法是这样的:
public ThreadPoolExecutor int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) {
corePoolSize: 核心线程的数量,当一个任务条件到线程池中执行时,只要线程的数量达不到corePoolSize的数量,就会建立新的线程,直到线程数量达到corePoolSize的大小,再也不建立,将新的任务放到阻塞队列中等待执行。 maximumPoolSize:线程池中容许建立最大线程数量,若是阻塞队列已满,建立的线程数量小于maximumPoolSize的话,会建立新的线程来处理阻塞队列中的任务。 keepAliveTime:线程活动的保持时间,当线程数量大于corePoolSize时,核心线程以外的线程空闲时间,大于该时间将会被回收。 unit:keepAliveTime的单位。 workQueue: 阻塞队列,当线程池中的线程数量为corePoolSize时,新来的任务会放到该阻塞队列中,有四种阻塞队列: ArrayBlockingQueue:基于数组的阻塞队列 LinkedBlockingQueue:基于链表的阻塞队列 SychronusBlockingQueue:不存储元素的阻塞队列(没见过) PriorityBlockingQueue:基于优先级的阻塞队列 threadFactory:建立线程的工厂 handler: 当阻塞队列满了,没有空闲线程的状况下,线程中的数量已经达到了最大数目,必须采起一种策略来处理新来的任务。主要有四种策略:AbortPolicy(直接抛出异常)、CallerRunsPolicy(使用调用者的线程处理)、DiscardOldsPolciy(丢弃阻塞队列中一个任务,处理当前任务)、Discard直接丢弃。
线程池对象有两个方法用来执行线程: submit()和execute()方法。
区别是submit()方法能够传入一个实现Callable()接口的对象,在当前任务结束的时候能返回一个Future对象来获取任务的返回值。 submit()方法仍是调用了execute()方法
public Future<?> submit(Runnable task) { if (task == null) throw new NullPointerException(); RunnableFuture<Void> ftask = newTaskFor(task, null); execute(ftask); return ftask; }
下面咱们重点来看一下execute()方法:
int c = ctl.get(); if (workerCountOf(c) < corePoolSize) { if (addWorker(command, true)) return; c = ctl.get(); } if (isRunning(c) && workQueue.offer(command)) { int recheck = ctl.get(); if (! isRunning(recheck) && remove(command)) reject(command); else if (workerCountOf(recheck) == 0) addWorker(null, false); } else if (!addWorker(command, false)) reject(command);
首先判断当前线程的数量与核心线程数量比较,若是小于核心线程的数量,直接建立一个新的worker线程
若是当前线程数量大于corePoolSize的数量,尝试添加任务到阻塞队列里面,而后第二次检查线程的数量,若是线程池状态不在RUNNING,直接移除,同时拒绝当前请求的任务,若是状态为RUNNING且线程的数量为0,建立一个新的线程。
若是当前状态不是RUNNING,则尝试建立一个新的worker来处理任务,若是建立失败,拒绝当前任务。
线程运行的四个阶段: 1.poolSize<corePoolSize 当前线程数量小于核心线程数量,直接建立线程来处理
2.poolSize=corePoolSize,并且此时阻塞队列没有满,将此任务添加到阻塞队列里面,若是此时存在工做线程(非核心线程),由工做线程来处理阻塞队列中的任务,若是工做线程数量为0,则会建立工做线程来处理 3. poolSize=corePoolSize 而且此时阻塞队列满了,直接建立新的工做线程来处理当前任务
4.poolSize=maxmumPoolSize:此时阻塞队列也满了,就会触发拒绝机制,具体什么策略由传入的RejectExceptionHandler决定
线程池重用线程,主要是在执行worker线程时候去阻塞队列里面拿任务,不断的去拿任务交给线程来执行,达到重用的目的,直到getTask为null为止。
final void runWorker(Worker w) { Thread wt = Thread.currentThread(); Runnable task = w.firstTask; w.firstTask = null; w.unlock(); // allow interrupts boolean completedAbruptly = true; try { while (task != null || (task = getTask()) != null) {
调用shutdown()和shutdownNow()方法
Java中经常使用线程池:
<p>newSingleThreadExecutor:建立一个单线程的线程池。这个线程池只有一个线程在工做,也就是至关于单线程串行执行全部任务。若是这个惟一的线程由于异常结束,那么会有一个新的线程来替代它。此线程池保证全部任务的执行顺序按照任务的提交顺序执行。</p> <p>newFixedThreadPool:建立固定大小的线程池。每次提交一个任务就建立一个线程,直到线程达到线程池的最大大小。线程池的大小一旦达到最大值就会保持不变,若是某个线程由于执行异常而结束,那么线程池会补充一个新线程。</p> <p>newCachedThreadPool:建立一个可缓存的线程池。若是线程池的大小超过了处理任务所须要的线程,那么就会回收部分空闲(60秒不执行任务)的线程,当任务数增长时,此线程池又能够智能的添加新线程来处理任务。此线程池不会对线程池大小作限制,线程池大小彻底依赖于操做系统(或者说JVM)可以建立的最大线程大小。</p> <p>newScheduledThreadPool:建立一个大小无限的线程池。此线程池支持定时以及周期性执行任务的需求。</p> <p>newSingleThreadExecutor:建立一个单线程的线程池。此线程池支持定时以及周期性执行任务的需求。</p>