Java提供了几种便捷的方法建立线程池,经过这些内置的api就可以很轻松的建立线程池。在java.util.concurrent包中的Executors类,其中的静态方法就是用来建立线程池的:java
上面那几个方法,其实都是建立了一个ThreadPoolExecutor对象做为返回值,要搞清楚线程池的原理主要仍是要分析ThreadPoolExecutor这个类。面试
ThreadPoolExecutor的构造方法:api
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) { ... }
ThreadPoolExecutor的构造方法包含如下几个参数:缓存
ThreadPoolExecutor中的线程统称为工做线程,但有一个小概念是核心线程,核心线程由参数corePoolSize指定,如corePoolSize设置5,那线程池中就会有5条线程常驻线程池中,不会被回收掉,可是也会有例外,若是allowCoreThreadTimeOut为true空闲一段时间后,也会被关闭。安全
线程中的状态和工做线程和数量都是由ctl表示,是一个AtomicInteger类型的属性:ide
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
ctl的高四位为线程的状态,其余位数为工做线程的数量,因此线程中最大的工做线程数量为(2^29)-1。oop
线程池中的状态有五种:性能
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0)); private static final int COUNT_BITS = Integer.SIZE - 3; private static final int CAPACITY = (1 << COUNT_BITS) - 1; // runState is stored in the high-order bits 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;
若是有面试官问:如何正确的建立线程池?千万不要说使用Executors建立线程,虽然Executors能很方便的建立线程池,可是他提供的静态建立方法会有一些坑。优化
主要的缘由是:maximumPoolSize和workQueue这两个参数ui
Executors静态方法在建立线程池时,若是maximumPoolSize设置为Integer.MAX_VALUE,这样会致使线程池能够一直要以接收运行任务,可能致使cpu负载太高。
workQueue是一个阻塞队列的实例,用于放置正在等待执行的任务。若是在建立线程种时workQueue实例没有指定任务的容量,那么等待队列中能够一直添加任务,极有可能致使oom。
因此建立线程,最好是根据线程池的用途,而后本身建立线程。
调用线程池的execute并非当即执行任务,线程池内部用通过一顿操做,如:判断核心线程数、是否须要添加到等待队列中。
下来的代码是execute的源码,代码很简洁只有2个if语句:
public void execute(Runnable command) { 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); }
换一种说法,在调用execute方法时,任务首先会放在Core Worker内,而后才是workQueue,最后才会考虑Worker。
这样作的缘由能够保证Core Worker中的任务执行完成后,能当即从workQueue获取下一个任务,而不须要启动别的工做线程,用最少的工做线程办更多的事。
在execute方法中,有三个地方调用了addWorker。addWorker方法能够分为二部分:
private boolean addWorker(Runnable firstTask, boolean core)
retry: for (;;) { int c = ctl.get(); int rs = runStateOf(c); .... for (;;) { int wc = workerCountOf(c); if (wc >= CAPACITY || wc >= (core ? corePoolSize : maximumPoolSize)) return false; if (compareAndIncrementWorkerCount(c)) break retry; c = ctl.get(); // Re-read ctl if (runStateOf(c) != rs) continue retry; // else CAS failed due to workerCount change; retry inner loop } }
上面代码省略了一部分代码,主要代码都在for循环中,利用CAS锁,安全的完成线程池状态的检查与增长工做线程的数量。其中的compareAndIncrementWorkerCount(c)调用就是将工做线程数量+1。
增长工做线程的数量后,紧接着就会启动工做线程:
boolean workerStarted = false; boolean workerAdded = false; Worker w = null; try { w = new Worker(firstTask); final Thread t = w.thread; if (t != null) { final ReentrantLock mainLock = this.mainLock; mainLock.lock(); try { // Recheck while holding lock. // Back out on ThreadFactory failure or if // shut down before lock acquired. int rs = runStateOf(ctl.get()); if (rs < SHUTDOWN || (rs == SHUTDOWN && firstTask == null)) { if (t.isAlive()) // precheck that t is startable throw new IllegalThreadStateException(); workers.add(w); int s = workers.size(); if (s > largestPoolSize) largestPoolSize = s; workerAdded = true; } } finally { mainLock.unlock(); } if (workerAdded) { t.start(); workerStarted = true; } } } finally { if (! workerStarted) addWorkerFailed(w); }
启动工做线程的流程:
w = new Worker(firstTask); final Thread t = w.thread;
就不说Worker类的实现了,直接给出构造方法来细品:
Worker(Runnable firstTask) { setState(-1); // inhibit interrupts until runWorker this.firstTask = firstTask; this.thread = getThreadFactory().newThread(this); }
if (rs < SHUTDOWN || (rs == SHUTDOWN && firstTask == null)) { if (t.isAlive()) // precheck that t is startable throw new IllegalThreadStateException(); workers.add(w); int s = workers.size(); if (s > largestPoolSize) largestPoolSize = s; workerAdded = true; }
注意::当线程池处于SHUTDOWN状态时,它不能接收新的任务,可是能够继续执行未完成的任务。任务是否从workQueue中获取,是根据firstTask判断,每一个Worker实例都有一个firstTask属性,若是这个值为null,工做线程启动的时候就会从workQueue中获取任务,不然会执行firstTask。
if (workerAdded) { t.start(); workerStarted = true; }
回过头来看一个Worker类的定义:
private final class Worker extends AbstractQueuedSynchronizer implements Runnable{ Worker(Runnable firstTask) { setState(-1); // inhibit interrupts until runWorker this.firstTask = firstTask; this.thread = getThreadFactory().newThread(this); } ... }
Worker类实现了Runnable接口,同时在构造方法中会将this传递给线程,到这里你就知道了Worker实例中有run方法,它会在线程启动后执行:
public void run() { runWorker(this); }
run方法内部接着调用runWorker方法运行任务,在这里才是真正的开始运行任务了:
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) { w.lock(); // If pool is stopping, ensure thread is interrupted; // if not, ensure thread is not interrupted. This // requires a recheck in second case to deal with // shutdownNow race while clearing interrupt if ((runStateAtLeast(ctl.get(), STOP) || (Thread.interrupted() && runStateAtLeast(ctl.get(), STOP))) && !wt.isInterrupted()) wt.interrupt(); try { beforeExecute(wt, task); Throwable thrown = null; try { task.run(); } catch (RuntimeException x) { thrown = x; throw x; } catch (Error x) { thrown = x; throw x; } catch (Throwable x) { thrown = x; throw new Error(x); } finally { afterExecute(task, thrown); } } finally { task = null; w.completedTasks++; w.unlock(); } } completedAbruptly = false; } finally { processWorkerExit(w, completedAbruptly); } }
Runnable task = w.firstTask;
而后循环检查task或者从workQueue中获取任务:
while (task != null || (task = getTask()) != null) { ... }
getTask()稍后再作分析。
while (task != null || (task = getTask()) != null) { ... task.run(); ... }
task其实就是经过调用execute方法传递进来的Runnable实例,也就是你的任务。只不过它可能保存在Worker.firstTask中,或者在workQueue中,保存在哪里在前面的任务添加顺序中已经说明。
试想一下若是每一个任务执行完成,就关闭掉一个线程那有多浪费资源,这样使用线程池也没有多大的意义。因此线程的主要的功能就是线程复用,一旦任务执行完成直接去获取下一个任务,或者挂起线程等待下一个提交的任务,而后等待一段时间后仍是没有任务提交,而后才考虑是否关闭部分空闲的线程。
runWorker中会循环的获取任务:
while (task != null || (task = getTask()) != null) { ... task.run(); ... }
上面的代码getTask()就是从workQueue中获取任务:
private Runnable getTask() { boolean timedOut = false; // Did the last poll() time out? for (;;) { ... int wc = workerCountOf(c); // Are workers subject to culling? boolean timed = allowCoreThreadTimeOut || wc > corePoolSize; ... try { Runnable r = timed ? workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) : workQueue.take(); if (r != null) return r; timedOut = true; } catch (InterruptedException retry) { timedOut = false; } } }
获取任务的时候会有两种方式:
仍是在runWorker方法中:
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) { task.run(); } completedAbruptly = false; } finally { processWorkerExit(w, completedAbruptly); } }
private void processWorkerExit(Worker w, boolean completedAbruptly) { if (completedAbruptly) // If abrupt, then workerCount wasn't adjusted decrementWorkerCount(); final ReentrantLock mainLock = this.mainLock; mainLock.lock(); try { completedTaskCount += w.completedTasks; workers.remove(w); } finally { mainLock.unlock(); } tryTerminate(); int c = ctl.get(); if (runStateLessThan(c, STOP)) { if (!completedAbruptly) { int min = allowCoreThreadTimeOut ? 0 : corePoolSize; if (min == 0 && ! workQueue.isEmpty()) min = 1; if (workerCountOf(c) >= min) return; // replacement not needed } addWorker(null, false); } }
processWorkerExit接收一个Worker实例与completedAbruptly变量。processWorkerExit的大体工做流程:
若是某个工做线程完成,线程池内部会判断是否须要从新启动一个:
//判断线程池状态 if (runStateLessThan(c, STOP)) { if (!completedAbruptly) { //获取最小工做线程数量 int min = allowCoreThreadTimeOut ? 0 : corePoolSize; //若是最小工做线程数量为0,可是workQueue中还有任务,那重置最小工做线程数量1 if (min == 0 && ! workQueue.isEmpty()) min = 1; //若是当前工做线程数数量大于或等于最小工做线程数量,则不须要启动新的工做线程 if (workerCountOf(c) >= min) return; // replacement not needed } //启动一个新的工做线程 addWorker(null, false); }
工做线程完成后有两种处理策略:
关闭线程池有能够经过shutdown方法:
public void shutdown() { final ReentrantLock mainLock = this.mainLock; mainLock.lock(); try { checkShutdownAccess(); advanceRunState(SHUTDOWN); interruptIdleWorkers(); onShutdown(); // hook for ScheduledThreadPoolExecutor } finally { mainLock.unlock(); } tryTerminate(); }
shutdown方法,第一步就是先改变线程池的状态,调用advanceRunState(SHUTDOWN)方法,将线程池当前状态更改成SHUTDOWN,advanceRunState代码以下:
private void advanceRunState(int targetState) { for (;;) { int c = ctl.get(); if (runStateAtLeast(c, targetState) || ctl.compareAndSet(c, ctlOf(targetState, workerCountOf(c)))) break; } }
而后当即调用interruptIdleWorkers()方法,interruptIdleWorkers()内部会调用它的重载方法interruptIdleWorkers(boolean onlyOne)同时onlyOne参数传递的false来关闭空闲的线程:
private void interruptIdleWorkers() { interruptIdleWorkers(false); } private void interruptIdleWorkers(boolean onlyOne) { final ReentrantLock mainLock = this.mainLock; mainLock.lock(); try { for (Worker w : workers) { Thread t = w.thread; if (!t.isInterrupted() && w.tryLock()) { try { t.interrupt(); } catch (SecurityException ignore) { } finally { w.unlock(); } } if (onlyOne) break; } } finally { mainLock.unlock(); } }
以上代码会遍历workers中的Worker实例,而后调用线程的interrupt()方法。
前面提到过在getTask()中,线程从workQueue中获取任务时会阻塞,被阻塞的线程就是空闲的。
再次回到getTask()的代码中:
private Runnable getTask() { boolean timedOut = false; // Did the last poll() time out? for (;;) { // Check if queue empty only if necessary. if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) { decrementWorkerCount(); return null; } ... int wc = workerCountOf(c); // Are workers subject to culling? boolean timed = allowCoreThreadTimeOut || wc > corePoolSize; ... try { Runnable r = timed ? workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) : workQueue.take(); if (r != null) return r; timedOut = true; } catch (InterruptedException retry) { timedOut = false; } } }
再次分析getTask()中的代码中有一段捕获InterruptedException的代码块,interruptIdleWorkers方法中断线程后,getTask()会捕获中断异常,由于外面是一个for循环,随后代码走到判断线程池状态的地方:
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) { decrementWorkerCount(); return null; }
上面的代码的会判断当前线程池状态,若是状态大于STOP或者状态等于SHUTDOWN而且workQueue为空时则返回null,getTask()返回空那么在runWorker中循环就会退出,当前工做线程的任务就完成了,能够退出了:
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) { task.run(); } completedAbruptly = false; } finally { processWorkerExit(w, completedAbruptly); } }
除了shutdown方法能关闭线程池,还有shutdownNow也能够关闭线程池。它两的区别在于:
public List<Runnable> shutdownNow() { List<Runnable> tasks; final ReentrantLock mainLock = this.mainLock; mainLock.lock(); try { checkShutdownAccess(); advanceRunState(STOP); interruptWorkers(); tasks = drainQueue(); } finally { mainLock.unlock(); } tryTerminate(); return tasks; }
上面代码基本流程:
调用shutdownNow()后线程池处于STOP状态,紧接着全部的工做线程都会被调用interrupt方法,若是此时runWorker还在运行会发生什么?
在runWorker有一段代码,就是工做线程停止的重要代码:
final void runWorker(Worker w) { ... while (task != null || (task = getTask()) != null) { if ((runStateAtLeast(ctl.get(), STOP) || (Thread.interrupted() && runStateAtLeast(ctl.get(), STOP))) && !wt.isInterrupted()) wt.interrupt(); task.run(); } ... }
重点关注:
if ((runStateAtLeast(ctl.get(), STOP) || (Thread.interrupted() && runStateAtLeast(ctl.get(), STOP))) && !wt.isInterrupted()) wt.interrupt();
这个if看起来有点难理解,理解下来大体意思是:若是线程池状态大于等于STOP,当即中断线程,不然清除线程的中断标记,也就是说当线程池状态为RUNNING和SHUTDOWN时,线程的中断标记会被清除(线程的中断代码在interruptWorkers方法中),能够继续执行任务。
以上代码执行完成后,紧接着就会调用task.run()方法,这里面咱们本身就能够根据线程的中断标记来判断任务是否被中断。
我的水平有限,文中若有错误,谢谢你们指正。
本文从线程池的源码入手,分析线程池的建立、添加任务、运行任务等流程,整个分析下来基本上大多数公司关于线程池面试的问题均可以回答得上来,固然还有一些小细节如:Worker类是继承AQS的,为何这么作其实源码中都有一些苗头,Worker在运行时会锁住运行的代码块,而shutdown在关闭空闲的Worker时,首先就要去获取Worker的同步锁才能继续操做,这样才能安全的关闭工做线程。
end