线程池
线程复用,减少线程的创建与销毁造成的性能损耗;
Executors 工具类
使用Executors 工具类创建的线程池有:newFixedThreadPool ; newCachedThreadPool ; newSingleThreadExecutor
它们都new了同一个对象(ThreadPoolExecutor),只是传的参数不同罢了,下面介绍一下ThreadPoolExecutor的各个参数:
public ThreadPoolExecutor(int corePoolSize, 核心线程数
int maximumPoolSize, 最大线程数
long keepAliveTime, 非核心线程最大空闲时间
TimeUnit unit, 时间单位
BlockingQueue<Runnable> workQueue, 工作队列,阻塞队列
ThreadFactory threadFactory, 线程工厂
RejectedExecutionHandler handler) 拒绝策略
jdk自带的拒绝策略有四种:
AbortPolicy : 抛异常
CallerRunsPolicy:运行新提交的任务
DisCardOldPolicy:抛弃旧的任务
DisCardPolicy:抛弃新提交的任务
常用的BlockingQueue:
用来保存等待被执行的任务的阻塞队列,且任务必须实现Runable接口,在JDK中提供 了如下阻塞队列:
1、ArrayBlockingQueue:基于数组结构的有界阻塞队列,按FIFO排序任务;
2、LinkedBlockingQuene:基于链表结构的无界阻塞队列,按FIFO排序任务,吞 吐量通常要高于ArrayBlockingQuene;
3、SynchronousQuene:一个不存储元素的阻塞队列,每个插入操作必须等到 另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于 LinkedBlockingQuene;
4、priorityBlockingQuene:具有优先级的无界阻塞队列;
阿里编码规范中并不建议我们使用Executors 工具创建线程池,我们来分析一下原因;
public static ExecutorService newFixedThreadPool(int nThreads) {
//创建的线程池,核心线程与最大线程一样;会导致线程一直存在,可能浪费系统资源;
//使用无限队列,任务提交时将会无限排队,可能造成内存溢出等;
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
public static ExecutorService newCachedThreadPool() {
//全部创建非核心线程,1分钟内闲置将全部销毁; 在任务执行间隙较大时会造成频繁的线程创建与销毁;
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
//只创建了一个线程,还是无限队列;
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
在线程池的创建过程中,都使用到了ThreadPoolExecutor类;下面着重进行分析;
ThreadPoolExecutor
// 用来描述线程池的状态 和 当前工作的线程数量; 使用高3位来描述线程池状态, 低29位描述工作线程的数量
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; //shutdown 不再接受新的任务,但是会执行完workQueue中的任务;
private static final int STOP = 1 << COUNT_BITS; // stop 不再接受新的任务,也不会执行workQueue中的任务;
private static final int TIDYING = 2 << COUNT_BITS; // workQueue为空, 工作线程为0时;
private static final int TERMINATED = 3 << COUNT_BITS; //线程终止
private final BlockingQueue<Runnable> workQueue; //workQueue
private final HashSet<Worker> workers = new HashSet<Worker>();//工作线程,泛型为Worker, Worker 也就对应一个线程;
源码分析
execute方法
{
if (command == null)
throw new NullPointerException();
// 获取线程池的状态
int c = ctl.get();
//如果工作线程小于核心线程时,优先把任务交给核心线程;
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
//如果线程池在运行状态,并且workQueue中可以添加新的任务,就添加到阻塞队列中
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);
}
addWorker
private boolean addWorker(Runnable firstTask, boolean core) {
retry:
for (;;) {
int c = ctl.get();
//获取线程的运行状态
int rs = runStateOf(c);
//>= SHUTDOWN 状态时,不再接受新任务;
//>= SHUTDOWN 时再判断
// !(rs==shutdown && 添加的firstTask==null && workQueue!= 空) 取反,也就是这3个条件有一个false 返回的就是true, 不添加work
if (rs >= SHUTDOWN &&
! (rs == SHUTDOWN &&
firstTask == null &&
! workQueue.isEmpty()))
return false;
for (;;) {
int wc = workerCountOf(c);
//当前的工作线程是否已经大于 最大值 || 当前的工作线程是否已经大于 核心线程 或 非核心线程, 这里取决于前面是否创建核心线程; 如果大于则不创建worker
if (wc >= CAPACITY ||
wc >= (core ? corePoolSize : maximumPoolSize))
return false;
// CAS worker数量+1, 如果成功就跳出到retry;
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 {
//创建新的Worker, Worker实现了Runable接口,继承了AbstractSyncQueue; 具备了线程 和 AQS的功能;
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());
//如果线程池的运行状态小于 shutdown时才添加worker
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();
}
//运行worker的run方法;
if (workerAdded) {
t.start();
workerStarted = true;
}
}
} finally {
if (! workerStarted)
addWorkerFailed(w);
}
return workerStarted;
}
Worker#run
一定要注意,每一个worker就是一个线程, 也是一个Lock;
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
//提交的第一个任务,从我们调用execute方法传入的;
Runnable task = w.firstTask;
w.firstTask = null;
w.unlock(); // allow interrupts
boolean completedAbruptly = true;
try {
//worker 执行firstTask 或者从 阻塞队列中获取任务;getTask();
// 如果能获取到任务就一直while循环执行,这也是为什么能够线程复用的核心逻辑;
while (task != null || (task = getTask()) != null) {
w.lock();
if ((runStateAtLeast(ctl.get(), STOP) ||
(Thread.interrupted() &&
runStateAtLeast(ctl.get(), STOP))) &&
!wt.isInterrupted())
wt.interrupt();
try {
beforeExecute(wt, task);
Throwable thrown = null;
try {
//执行传入的Runable的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 {
//不能获得任务,或者抛出异常时的逻辑;
processWorkerExit(w, completedAbruptly);
}
}
getTask()
private Runnable getTask() {
boolean timedOut = false; // Did the last poll() time out?
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
// 如果线程池运行状态 >= shutdown, 并且rs > shutdown 或 workQueue为空;将工作线程-1;
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
decrementWorkerCount();
return null;
}
int wc = workerCountOf(c);
// allowCoreThreadTimeOut 核心线程是否使用闲置过期策略,默认为false;
// 当工作线程大于核心线程时这里为 true; 准备关闭闲置非核心线程;
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
//如果工作线程大于最大线程数 或者 非核心线程已经超时了; 并且工作线程>1 将工作线程数量-1;
if ((wc > maximumPoolSize || (timed && timedOut))
&& (wc > 1 || workQueue.isEmpty())) {
if (compareAndDecrementWorkerCount(c))
return null;
continue;
}
try {
// 如果满足了工作线程大于核心线程时, 将使用超时时间获取队列内容的方式,时间内能获取则正常返回,不正常获取返回null;
// 如果不满足工作线程大于核心线程时,使用take 阻塞线程,直到能获取到内容;
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
workQueue.take();
if (r != null)
return r;
//走到这里表示返回的为null, 已经超时了,下次循环时会清理此Worker;
//下次循环时,返回null, 那么上层的while循环也将退出,worker线程正常死亡;
timedOut = true;
} catch (InterruptedException retry) {
timedOut = false;
}
}
}