文章目录
线程池概述
使用线程池的优点
- 可以降低资源的消耗,通过重复使用已经创建的线程,可以降低创建线程和销毁线程带来的消耗
- 提高响应速度,当任务到达时,不需要等待线程创建就能立即执行
- 提高线程的可管理性,线程是稀缺资源,如果无限制的创建和销毁,不光会带来资源的消耗,还会降低系统的稳定性,通过线程池,可以对线程进行统一的分配,调优和监控
线程池处理流程
主线程执行execute添加任务,线程池创建工作线程,执行任务,再次拉取工作队列任务,直到工作队列没有任务,阻塞工作线程
工作线程阻塞在工作队列,主线程执行execute添加任务到工作队列,工作线程被唤醒,拿到工作队列中的任务执行,执行完毕,再次拉取工作队列任务,直到工作队列没有任务,阻塞工作线程
常见线程池介绍
Executors 类提供了四种不同线程池:newCachedThreadPool
,newFixedThreadPool
,newSingleThreadExecutor
,newScheduledThreadPool
- newCachedThreadPool
用来创建一个可以无限扩大的线程池,适用于负载较轻的场景,执行短期异步任务。(可以使得任务快速得到执行,因为任务时间执行短,可以很快的结束,不会照成cpu过度切换)
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
- newFixedThreadPool
创建一个固定大小的线程池,因为采用无界的阻塞队列,所以实际线程数量永远不会变化,适用于负载较重的场景,对当前线程数量进行限制。(保证线程数可控,不会照成线程过多,导致系统负责更为严重)
public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(),
threadFactory);
}
- newSingleThreadExecutor
创建一个单线程的线程池,适用于保证顺序执行各个任务
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
- newScheduledThreadPool
适用于执行延时或者周期任务
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue());
}
线程池主要参数
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> 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;
}
- corePoolSize (线程池基本大小、核心线程数)
当向线程池提交一个任务时,若线程池已创建的线程数小于 corePoolSize ,即便此时存在空闲的线程,也会通过创建一个新线程来执行该任务,直到已创建的线程数大于或等于 corePoolSize
核心线程数设置方案:
CPU 密集型(代表当前线程一直在执行指令):将核心线程数设置为cpu内核数 + 1
IO 密集型(IO调用比较多,调用远程服务,查询数据库等):将核心线程数设置为cpu内核数 * 2
混合密集型:可拆分出具体任务,设置两个线程池,分别执行cpu密集任务和io密集任务
-
maximumPoolSize (线程池最大大小)
线程池所允许的最大线程个数。当队列满了,且已创建的线程数小于maximumPoolSize ,则线程池会创建新的线程来执行任务。另外,对于无界队列,可以忽略该参数 -
keepAliveTime(线程存活保持时间)
当线程池中线程数大于核心线程数时,线程的空闲时间如果超过线程存活时间,那么这个线程就会被销毁,直到线程池中的线程数小于等于核心线程数 -
workQueue(任务队列)
用于传输和保存等待执行任务的阻塞队列 -
threadFactory(线程工厂)
用于创建新线程。threadFactory 创建的线程也是采用 new Thread() 的方式,threadFactory 创建的线程名具有统一的风格:pool-m-thread-n(m为线程池的编号,n为线程池内的线程编号) -
handler(线程饱和策略)
当线程池和队列都满了,再加入线程会执行此策略
线程池状态
AtomicInteger 修饰的 ctl 维护这线程池的2个核心内容:
-
线程池状态(高3位,维护着线程池状态)
-
工作线程数量(核心线程+非核心线程,低29位,维护着工作线程个数)
相关源码
// 高三位 线程池状态
// 低29位 核心线程数 + 非核心线程数
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
// COUNT_BITS=29
private static final int COUNT_BITS = Integer.SIZE - 3;
// 工作线程的最大个数
// 1 << COUNT_BITS = 00100000 00000000 00000000 00000000
// 00100000 00000000 00000000 00000000 - 1 =
// 00011111 11111111 11111111 11111111
private static final int CAPACITY = (1 << COUNT_BITS) - 1;
// 拿到线程池状态
// ~CAPACITY = 11100000 00000000 00000000 00000000
private static int runStateOf(int c) { return c & ~CAPACITY; }
// 拿到工作线程个数
// CAPACITY = 00011111 11111111 11111111 11111111
private static int workerCountOf(int c) { return c & CAPACITY; }
// 线程状态
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;
ThreadPoolExecutor 源码解析
execute()
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
int c = ctl.get();
// 工作线程 < 核心线程
if (workerCountOf(c) < corePoolSize) {
// 尝试添加核心线程 true - 核心线程 false - 非核心线程
if (addWorker(command, true))
return;
// 添加核心线程失败重新获取ctl
c = ctl.get();
}
// 线程池状态是 RUNNING && 添加任务到工作队列
if (isRunning(c) && workQueue.offer(command)) {
// 再次获取ctl
int recheck = ctl.get();
// 状态不为 RUNNING && 把任务从工作队列移除
if (! isRunning(recheck) && remove(command))
//走拒绝策略
reject(command);
// 工作线程状态是 RUNNING && 工作线程数是0
// 原因:1.将核心线程设置为 0 ,所有工作线程都是非核心线程
// 2. 核心线程全部超时被销毁
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 (;;) {
// 获取ctl
int c = ctl.get();
// 获取线程状态
int rs = runStateOf(c);
// 线程状态 >= SHUTDOWN &&
// !(线程状态 = SHUTDOWN && firstTask == null && 工作队列不为空) 此时还要处理工作队列中的任务
if (rs >= SHUTDOWN &&
! (rs == SHUTDOWN &&
firstTask == null &&
! workQueue.isEmpty()))
return false;
for (;;) {
// 获取工作线程个数
int wc = workerCountOf(c);
// wc >= 工作线程最大个数 ||
// wc >= true - 核心线程 false - 非核心线程
if (wc >= CAPACITY ||
wc >= (core ? corePoolSize : maximumPoolSize))
return false;
// 对 ctl + 1
if (compareAndIncrementWorkerCount(c))
break retry;
c = ctl.get(); // Re-read ctl
// 线程状态发生变化,跳出 retry 重新执行
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中
w = new Worker(firstTask);
final Thread t = w.thread;
if (t != null) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// 线程状态
int rs = runStateOf(ctl.get());
if (rs < SHUTDOWN ||
(rs == SHUTDOWN && firstTask == null)) {
// 线程已启动抛异常
if (t.isAlive())
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;
}
addWorkerFailed()
添加工作线程失败时执行,类似于回滚
private void addWorkerFailed(Worker w) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// 说明worker可能存放到了workers的hashSet中。
if (w != null)
// 移除!
workers.remove(w);
// 减掉workerCount的数值 -1
decrementWorkerCount();
// 尝试干掉自己
tryTerminate();
} finally {
mainLock.unlock();
}
}
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 {
// 如果Worker自身携带任务,直接执行
// 如果Worker携带的是null,通过getTask去工作队列获取任务
while (task != null || (task = getTask()) != null) {
w.lock();
// 判断线程池状态是否大于等于STOP,如果是要中断当前线程
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);
}
}
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);
// allowCoreThreadTimeOut - 核心线程是否允许超时
// || 工作线程个数 > 核心线程个数
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
// 判断工作线程是否超过了最大线程数 && 工作队列为null
if ((wc > maximumPoolSize || (timed && timedOut))
&& (wc > 1 || workQueue.isEmpty())) {
// 对工作线程个数--
if (compareAndDecrementWorkerCount(c))
return null;
continue;
}
try {
// 如果是非核心,走poll,拉取工作队列任务,
// 如果是核心线程,走take一直阻塞,拉取工作队列任务
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
workQueue.take();
if (r != null)
return r;
timedOut = true;
} catch (InterruptedException retry) {
timedOut = false;
}
}
}
processWorkerExit()
干掉当前工作线程,判断当前工作线程个数是否需要增加,如果需要添加非核心空任务的线程处理工作队列中的任务
private void processWorkerExit(Worker w, boolean completedAbruptly) {
// 如果是不正常操作,需要先对工作线程数-- (如果正常情况,getTask就--了)
if (completedAbruptly)
decrementWorkerCount();
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// 将当前工作线程完整的任务个数赋值给整个线程池中的任务数
completedTaskCount += w.completedTasks;
// 干掉当前工作线程
workers.remove(w);
} finally {
mainLock.unlock();
}
// 线程池是否可以中止,线程池状态是否发生变化。
tryTerminate();
int c = ctl.get();
//如果当前线程池状态小于STOP
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);
}
}