JUC(java.util.concurrent)线程池工具类Executors是我们常用的类,处理大批量任务时,非常重要,提供程序的并发能力。
虽然很多编码规范(A公司)不推荐使用此工具类,只有明白线程池的工作原理才能在适当的情况下使用。
1. Executors用法
有3大类,分别是红黄蓝()标记
1)常规线程池
2)定时线程池
3)fork/join线程池,JDK8新增功能
2. 常规线程池
2.1 日常使用的线程池原理
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue());
}
public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue(),
threadFactory);
}
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue());
}
public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue(),
threadFactory);
}
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue()));
}
public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue(),
threadFactory));
}
共6种实现
可以看出他们的本质是ThreadPoolExecutor。
2.2 ThreadPoolExecutor的工作方式
构造函数分析
/**
* Creates a new {@code ThreadPoolExecutor} with the given initial
* parameters.
*
* @param corePoolSize the number of threads to keep in the pool, even
* if they are idle, unless {@code allowCoreThreadTimeOut} is set
* @param maximumPoolSize the maximum number of threads to allow in the
* pool
* @param keepAliveTime when the number of threads is greater than
* the core, this is the maximum time that excess idle threads
* will wait for new tasks before terminating.
* @param unit the time unit for the {@code keepAliveTime} argument
* @param workQueue the queue to use for holding tasks before they are
* executed. This queue will hold only the {@code Runnable}
* tasks submitted by the {@code execute} method.
* @param threadFactory the factory to use when the executor
* creates a new thread
* @param handler the handler to use when execution is blocked
* because the thread bounds and queue capacities are reached
* @throws IllegalArgumentException if one of the following holds:
* {@code corePoolSize < 0}
* {@code keepAliveTime < 0}
* {@code maximumPoolSize <= 0}
* {@code maximumPoolSize < corePoolSize}
* @throws NullPointerException if {@code workQueue}
* or {@code threadFactory} or {@code handler} is null
*/
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
if (corePoolSize < 0 ||
maximumPoolSize <= 0 ||
maximumPoolSize < corePoolSize ||
keepAliveTime < 0)
throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.acc = System.getSecurityManager() == null ?
null :
AccessController.getContext();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
具体参数不细介绍了,看我的博文线程池ThreadPoolExecutor
ThreadPoolExecutor继承关系
我们知道线程池的提交模式是submit方法和execute方法。下面看这些方法的实现原理和区别。
2.2.1 execute方法
先看execute方法,在Executor中定义,Runnable接口参数,没有返回值,线程池没有计算的结果返回。
public interface Executor {
/**
* Executes the given command at some time in the future. The command
* may execute in a new thread, in a pooled thread, or in the calling
* thread, at the discretion of the {@code Executor} implementation.
*
* @param command the runnable task
* @throws RejectedExecutionException if this task cannot be
* accepted for execution
* @throws NullPointerException if command is null
*/
void execute(Runnable command);
}
ThreadPoolExecutor的方法源码
看这段代码需要位运算的知识(摘录自http://www.runoob.com/java/java-operators.html)
操作符 | 描述 | 例子 |
---|---|---|
& | 如果相对应位都是1,则结果为1,否则为0 | (A&B),得到12,即0000 1100 |
| | 如果相对应位都是0,则结果为0,否则为1 | (A | B)得到61,即 0011 1101 |
^ | 如果相对应位值相同,则结果为0,否则为1 | (A ^ B)得到49,即 0011 0001 |
〜 | 按位取反运算符翻转操作数的每一位,即0变成1,1变成0。 | (〜A)得到-61,即1100 0011 |
<< | 按位左移运算符。左操作数按位左移右操作数指定的位数。 | A << 2得到240,即 1111 0000 |
>> | 按位右移运算符。左操作数按位右移右操作数指定的位数。 | A >> 2得到15即 1111 |
>>> | 按位右移补零操作符。左操作数的值按右操作数指定的位数右移,移动得到的空位以零填充。 | A>>>2得到15即0000 1111 |
//初始化-536870912。存放线程池的有效线程数和线程池的运行状态
/**
* In order to pack them into one int, we limit workerCount to
* (2^29)-1 (about 500 million) threads rather than (2^31)-1 (2
* billion) otherwise representable. If this is ever an issue in
* the future, the variable can be changed to be an AtomicLong,
* and the shift/mask constants below adjusted. But until the need
* arises, this code is a bit faster and simpler using an int.
*/
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
//可以看出状态码是-1 0 1 2 3 位移29位
//可以看出running的状态小于0 -1位移29位为负整数,每次添加一个线程,做++操作。
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;
// Packing and unpacking ctl
private static int runStateOf(int c) { return c & ~CAPACITY; }
private static int workerCountOf(int c) { return c & CAPACITY; }
private static int ctlOf(int rs, int wc) { return rs | wc; }
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
/*
* Proceed in 3 steps:
*
* 1. If fewer than corePoolSize threads are running, try to
* start a new thread with the given command as its first
* task. The call to addWorker atomically checks runState and
* workerCount, and so prevents false alarms that would add
* threads when it shouldn't, by returning false.
*
* 2. If a task can be successfully queued, then we still need
* to double-check whether we should have added a thread
* (because existing ones died since last checking) or that
* the pool shut down since entry into this method. So we
* recheck state and if necessary roll back the enqueuing if
* stopped, or start a new thread if there are none.
*
* 3. If we cannot queue task, then we try to add a new
* thread. If it fails, we know we are shut down or saturated
* and so reject the task.
*/
//AtomicInteger存
int c = ctl.get();
//工作线程小于corePoolSize
if (workerCountOf(c) < corePoolSize) {
//添加一个core线程,此处参数为true,表示添加的线程是core容量下的线程
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);
//线程池在运行,有效线程数为0
else if (workerCountOf(recheck) == 0)
//添加一个空线程进线程池,使用非core容量线程
//仅有一种情况,会走这步,core线程数为0,max线程数>0,队列容量>0
//创建一个非core容量的线程,线程池会将队列的command执行
addWorker(null, false);
}
//线程池停止了或者队列已满,添加maximumPoolSize容量工作线程,如果失败,执行拒绝策略
else if (!addWorker(command, false))
reject(command);
}
final void reject(Runnable command) {
handler.rejectedExecution(command, this);
}
看上面的英文注释,有3步:
1) 检查core线程池数量
2)如果corePoolSize线程数量已使用,如果队列容量未满,则加入队列。
3)队列已满,创建maximumPoolSize线程数量执行;如果失败则执行关闭线程池或者拒绝策略。
继续跟踪
private boolean addWorker(Runnable firstTask, boolean core)
private final ReentrantLock mainLock = new ReentrantLock();
private final HashSet workers = new HashSet();
/**
* Checks if a new worker can be added with respect to current
* pool state and the given bound (either core or maximum). If so,
* the worker count is adjusted accordingly, and, if possible, a
* new worker is created and started, running firstTask as its
* first task. This method returns false if the pool is stopped or
* eligible to shut down. It also returns false if the thread
* factory fails to create a thread when asked. If the thread
* creation fails, either due to the thread factory returning
* null, or due to an exception (typically OutOfMemoryError in
* Thread.start()), we roll back cleanly.
*
* @param firstTask the task the new thread should run first (or
* null if none). Workers are created with an initial first task
* (in method execute()) to bypass queuing when there are fewer
* than corePoolSize threads (in which case we always start one),
* or when the queue is full (in which case we must bypass queue).
* Initially idle threads are usually created via
* prestartCoreThread or to replace other dying workers.
*
* @param core if true use corePoolSize as bound, else
* maximumPoolSize. (A boolean indicator is used here rather than a
* value to ensure reads of fresh values after checking other pool
* state).
* @return true if successful
*/
private boolean addWorker(Runnable firstTask, boolean core) {
//自旋检查
retry:
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
// Check if queue empty only if necessary.
//如果线程池已关闭;线程池正在关闭,提交的任务为null,任务队列不为空,则直接返回失败
if (rs >= SHUTDOWN &&
! (rs == SHUTDOWN &&
firstTask == null &&
! workQueue.isEmpty()))
return false;
for (;;) {
int wc = workerCountOf(c);
//工作线程数达到或超过最大容量,或者添加core线程达到最大容量或者添加max线程达到最大容量,直接失败
if (wc >= CAPACITY ||
wc >= (core ? corePoolSize : maximumPoolSize))
return false;
//线程数+1,CAS原子操作,成功后跳出循环
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
}
}
boolean workerStarted = false;
boolean workerAdded = false;
Worker w = null;
try {
//所有代码的核心,new Worker,创建了线程,或者复用线程
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();
//添加线程存储,HashSet存储
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);
}
return workerStarted;
}
继续跟踪
//所有代码的核心,new Worker,创建了线程,或者复用线程
w = new Worker(firstTask);
Worker是啥
private final class Worker
extends AbstractQueuedSynchronizer
implements Runnable
{
/**
* This class will never be serialized, but we provide a
* serialVersionUID to suppress a javac warning.
*/
private static final long serialVersionUID = 6138294804551838833L;
/** Thread this worker is running in. Null if factory fails. */
final Thread thread;
/** Initial task to run. Possibly null. */
Runnable firstTask;
/** Per-thread task counter */
volatile long completedTasks;
/**
* Creates with given first task and thread from ThreadFactory.
* @param firstTask the first task (null if none)
*/
Worker(Runnable firstTask) {
setState(-1); // inhibit interrupts until runWorker
this.firstTask = firstTask;
//此处创建了线程,线程工厂,使用this
this.thread = getThreadFactory().newThread(this);
}
/** Delegates main run loop to outer runWorker */
public void run() {
runWorker(this);
}
Worker实现AQS和Runnable接口 ,是线程接口实现
追踪run方法
/**
* Main worker run loop. Repeatedly gets tasks from queue and
* executes them, while coping with a number of issues:
*
* 1. We may start out with an initial task, in which case we
* don't need to get the first one. Otherwise, as long as pool is
* running, we get tasks from getTask. If it returns null then the
* worker exits due to changed pool state or configuration
* parameters. Other exits result from exception throws in
* external code, in which case completedAbruptly holds, which
* usually leads processWorkerExit to replace this thread.
*
* 2. Before running any task, the lock is acquired to prevent
* other pool interrupts while the task is executing, and then we
* ensure that unless pool is stopping, this thread does not have
* its interrupt set.
*
* 3. Each task run is preceded by a call to beforeExecute, which
* might throw an exception, in which case we cause thread to die
* (breaking loop with completedAbruptly true) without processing
* the task.
*
* 4. Assuming beforeExecute completes normally, we run the task,
* gathering any of its thrown exceptions to send to afterExecute.
* We separately handle RuntimeException, Error (both of which the
* specs guarantee that we trap) and arbitrary Throwables.
* Because we cannot rethrow Throwables within Runnable.run, we
* wrap them within Errors on the way out (to the thread's
* UncaughtExceptionHandler). Any thrown exception also
* conservatively causes thread to die.
*
* 5. After task.run completes, we call afterExecute, which may
* also throw an exception, which will also cause thread to
* die. According to JLS Sec 14.20, this exception is the one that
* will be in effect even if task.run throws.
*
* The net effect of the exception mechanics is that afterExecute
* and the thread's UncaughtExceptionHandler have as accurate
* information as we can provide about any problems encountered by
* user code.
*
* @param w the worker
*/
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
Runnable task = w.firstTask;
w.firstTask = null;
//任务线程的锁状态默认为-1(构造函数设置的),此时解锁+1,变为0,是锁打开状态,允许中断。
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 {
//本质,直接调用run方法
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 {
//worker结束处理
processWorkerExit(w, completedAbruptly);
}
}
跟踪getTask
getTask()
private Runnable getTask() {
boolean timedOut = false; // Did the last poll() time out?
//自旋锁
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
// 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;
//工作线程数超过core或者max,或者队列为空,工作线程存在
if ((wc > maximumPoolSize || (timed && timedOut))
&& (wc > 1 || workQueue.isEmpty())) {
//减少任务数
if (compareAndDecrementWorkerCount(c))
return null;
continue;
}
try {
//超时机制控制队列取元素
//take 移除并返回队列头部的元素 如果队列为空,则阻塞
//poll 移除并返问队列头部的元素 如果队列为空,则返回null
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
workQueue.take();
if (r != null)
return r;
timedOut = true;
} catch (InterruptedException retry) {
timedOut = false;
}
}
}
跟踪
processWorkerExit(w, completedAbruptly);
/**
* Performs cleanup and bookkeeping for a dying worker. Called
* only from worker threads. Unless completedAbruptly is set,
* assumes that workerCount has already been adjusted to account
* for exit. This method removes thread from worker set, and
* possibly terminates the pool or replaces the worker if either
* it exited due to user task exception or if fewer than
* corePoolSize workers are running or queue is non-empty but
* there are no workers.
*
* @param w the worker
* @param completedAbruptly if the worker died due to user exception
*/
private void processWorkerExit(Worker w, boolean completedAbruptly) {
//正常执行,此处设置为法false
if (completedAbruptly) // If abrupt, then workerCount wasn't adjusted
decrementWorkerCount();
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
//任务数增加
completedTaskCount += w.completedTasks;
//移除HashSet的线程
workers.remove(w);
} finally {
mainLock.unlock();
}
//尝试停止线程池
tryTerminate();
int c = ctl.get();
//如果没有停止线程池
if (runStateLessThan(c, STOP)) {
if (!completedAbruptly) {
int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
//core线程数量为0或者队列为空,默认1
if (min == 0 && ! workQueue.isEmpty())
min = 1;
//工作线程比core线程多,直接返回
if (workerCountOf(c) >= min)
return; // replacement not needed
}
//当前线程运行结束,增加空线程,容量maximumPoolSize
addWorker(null, false);
}
}
addWorker失败处理
addWorkerFailed(w);
/**
* Rolls back the worker thread creation.
* - removes worker from workers, if present
* - decrements worker count
* - rechecks for termination, in case the existence of this
* worker was holding up termination
*/
private void addWorkerFailed(Worker w) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
if (w != null)
//工作线程移除任务HashSet
workers.remove(w);
//工作线程数量-1
decrementWorkerCount();
//尝试停止线程池
tryTerminate();
} finally {
mainLock.unlock();
}
}
tryTerminate
/**
* Transitions to TERMINATED state if either (SHUTDOWN and pool
* and queue empty) or (STOP and pool empty). If otherwise
* eligible to terminate but workerCount is nonzero, interrupts an
* idle worker to ensure that shutdown signals propagate. This
* method must be called following any action that might make
* termination possible -- reducing worker count or removing tasks
* from the queue during shutdown. The method is non-private to
* allow access from ScheduledThreadPoolExecutor.
*/
final void tryTerminate() {
for (;;) {
int c = ctl.get();
//线程池在运行或者状态在变化中,或者正在停止但队列有任务,直接返回
if (isRunning(c) ||
runStateAtLeast(c, TIDYING) ||
(runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
return;
//有任务工作线程
if (workerCountOf(c) != 0) { // Eligible to terminate
//中断所有线程
interruptIdleWorkers(ONLY_ONE);
return;
}
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
//线程池状态改变
if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
try {
//结束线程池,空方法,does nothing
terminated();
} finally {
//设置线程池状态,结束
ctl.set(ctlOf(TERMINATED, 0));
//唤醒所有wait线程
termination.signalAll();
}
return;
}
} finally {
mainLock.unlock();
}
// else retry on failed CAS
}
}
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();
}
}
/**
* Method invoked when the Executor has terminated. Default
* implementation does nothing. Note: To properly nest multiple
* overridings, subclasses should generally invoke
* {@code super.terminated} within this method.
*/
protected void terminated() { }
大量的CAS和自旋锁;位运算算法和重入锁AQS。
看看销毁线程池方法
shutdown()
public void shutdown() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
//检查权限
checkShutdownAccess();
//CAS 更新线程池状态
advanceRunState(SHUTDOWN);
//中断所有线程
interruptIdleWorkers();
//关闭,此处是do nothing
onShutdown(); // hook for ScheduledThreadPoolExecutor
} finally {
mainLock.unlock();
}
//尝试结束,上面代码已分析
tryTerminate();
}
2.2.2 submit方法
/**
* @throws RejectedExecutionException {@inheritDoc}
* @throws NullPointerException {@inheritDoc}
*/
public Future> submit(Runnable task) {
if (task == null) throw new NullPointerException();
RunnableFuture ftask = newTaskFor(task, null);
execute(ftask);
return ftask;
}
/**
* @throws RejectedExecutionException {@inheritDoc}
* @throws NullPointerException {@inheritDoc}
*/
public Future submit(Runnable task, T result) {
if (task == null) throw new NullPointerException();
RunnableFuture ftask = newTaskFor(task, result);
execute(ftask);
return ftask;
}
/**
* @throws RejectedExecutionException {@inheritDoc}
* @throws NullPointerException {@inheritDoc}
*/
public Future submit(Callable task) {
if (task == null) throw new NullPointerException();
RunnableFuture ftask = newTaskFor(task);
execute(ftask);
return ftask;
}
调用的execute方法,只是多了newTaskFor,用来收集线程的运算结果。
3. 总结
1)线程池优先使用corePoolSize的数量执行工作任务
2)如果超过corePoolSize,队列入队
3)超过队列,使用maximumPoolSize-corePoolSize的线程处理,这部分线程超时不干活就销毁掉。
4)每个线程执行结束的时候,会判断当前的工作线程和任务数,如果任务数多,就会创建空线程从队列拿任务。
5)线程池执行完成,不会自动销毁,需要手工shutdown,修改线程池状态,中断所有线程。