1. 线程池7大参数
1.0 线程池工作原理
//存放工作线程的集合
private final HashSet workers = new HashSet();
//代表一个工作线程
Worker
worker 实现runnable接口 代表可执行任务
—属性:
1. final Thread thread // 具体工作的线程
2. Runnable firstTask // 需要执行的任务
-----a
自己语言描述
worker 线程池工作的核心类
线程池每当创建一个工作线程,实际上就是创建一个worker类,worker 里面有2个属性 thread,和Runnable,用thread 来执行runworker方法,runworker方法执行 提交的任务。任务执行完后,runworker方法不会停止,使用while循环不断的区任务队列里面获取任务。
worker 类在addworker方法里面 创建对象,执行start方法。
ExecutorService threadPoolExecutor = new ThreadPoolExecutor(2, 2,
60, TimeUnit.SECONDS,
new LinkedBlockingDeque<>(2),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.CallerRunsPolicy());
1.6 线程池工厂
1.7 线程池拒绝策略
多线程四种拒绝策略
这四种拒绝策略,在ThreadPoolExecutor是四个内部类。
AbortPolicy abortPolicy = new ThreadPoolExecutor.AbortPolicy();
DiscardPolicy discardPolicy = new ThreadPoolExecutor.DiscardPolicy();
DiscardOldestPolicy discardOldestPolicy =new ThreadPoolExecutor.DiscardOldestPolicy();
CallerRunsPolicy callerRunsPolicy = new ThreadPoolExecutor.CallerRunsPolicy();
- AbortPolicy
当任务添加到线程池中被拒绝时,直接丢弃任务,并抛出
RejectedExecutionException异常。
- DiscardPolicy
当任务添加到线程池中被拒绝时,丢弃被拒绝的任务,不抛异常。
- DiscardOldestPolicy
当任务添加到线程池中被拒绝时,丢弃任务队列中最旧的未处理任务,然后将被拒绝的任务添加到等待队列中。
- CallerRunsPolicy
被拒绝任务的处理程序,直接在execute方法的调用线程中运行被拒绝的任务。
总结:就是被拒绝的任务,直接在主线程中运行,不再进入线程池。
2.线程池执行流程
3.ThreadPoolExecutor状态
3.1 ctl
//int 类型的数值
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
// Integer.SIZE=32
//ctl 表示两种状态
//1.表示线程池当前的工作状态(高三位)
//2.表示线程池当前的工作线程数(低29位)
private static final int COUNT_BITS = Integer.SIZE - 3;//29
//工作线程最大容量
//00011111 11111111 11111111 11111111
private static final int CAPACITY = (1 << COUNT_BITS) - 1;
//1<<29 00100000 00000000 00000000 00000000
//1<<29-1 0001111 11111111 11111111 11111111
// runState is stored in the high-order bits
// 线程池的五种状态
// -1 -> 11111111 11111111 11111111 11111111
// -1<<29 11100000 00000000 00000000 00000000
private static final int RUNNING = -1 << COUNT_BITS;
//000
private static final int SHUTDOWN = 0 << COUNT_BITS;
//001 ...
private static final int STOP = 1 << COUNT_BITS;
//010 ...
private static final int TIDYING = 2 << COUNT_BITS;
//110 ...
private static final int TERMINATED = 3 << COUNT_BITS;
// Packing and unpacking ctl
//计算出当前线程池的状态
// ~CAPACITY -> 11100000 00000000 00000000 00000000
private static int runStateOf(int c) {
return c & ~CAPACITY; }
// 计算当前线程池的数量
private static int workerCountOf(int c) {
//00011111 11111111 11111111 11111111
return c & CAPACITY; }
// rs 为高 3 位代表线程池状态, wc 为低 29 位代表线程个数,ctl 是合并它们
private static int ctlOf(int rs, int wc) {
return rs | wc; }
3.2 线程池状态过程
terminated tidying stop shutdown running
4 线程池 核心方法
4.1 execute()
为什么线程池为添加一个空任务的非核心线程
为了解决 工作线程为0,但是工作队列有任务i的状态
public void execute(Runnable command) {
//非空判断
if (command == null)
throw new NullPointerException();
//获取ctl属性
int c = ctl.get();
// 获取线程池工作线程的个数 是否小于核心线程
if (workerCountOf(c) < corePoolSize) {
//添加一个任务让核心线程执行
if (addWorker(command, true))
//成功 返回true
return;
// 添加任务让核心线程执行失败,比如多个线程并发情况下
// 都执行execute
// 只有一个成功 那么重新获取ctl
c = ctl.get();
}
//创建核心线程失败
// 判断当前线程池的状态是否running 是 && 将任务添加到任务队列
if (isRunning(c) && workQueue.offer(command)) {
//添加任务到工作队列成功 重新获取ctl
int recheck = ctl.get();
// 判断线程池是否是running
// 不是running状态 需要将任务从工作队列移除
// 添加完任务 做一个状态的重新检查
if (! isRunning(recheck) && remove(command))
//线程池状态不正确,执行拒绝策略
reject(command);
// 是running 或者移除任务失败 判断工作线程数是否为0
else if (workerCountOf(recheck) == 0)
// 此时 工作队列有任务,但是没有工作线程数
// 添加一个空任务,非核心线程,处理在工作队列中排队的任务
addWorker(null, false);
}
// 任务添加到工作队列失败 尝试创建非核心线程,也就是救急线程
else if (!addWorker(command, false))
// 创建非核心线程失败 执行拒绝策略
reject(command);
}
4.2 addWorker()
// 添加核心线程处理任务
工作队列有任务,但是没有工作线程 ,添加非核心线程处理工作队列的任务
添加非核心线程处理任务
功能 添加工作线程到workers set集合中 并启动工作线程 start ,
- 判断线程池状态 和线程工作数量
- 添加工作线程,并启动工作线程
private boolean addWorker(Runnable firstTask, boolean core) {
//break 内层 跳出外层for循环
retry:
//------------
//对线程池状态的判断,以及对工作线程数量的判断
for (;;) {
//获取ctl
int c = ctl.get();
//获取线程池状态
int rs = runStateOf(c);
// Check if queue empty only if necessary.
// rs >= SHUTDOWN 当前线程不是running, running 属性小于0
//查看当前任务是否可以不处理
if (rs >= SHUTDOWN &&
! (rs == SHUTDOWN &&
firstTask == null &&
! workQueue.isEmpty()))
//线程池状态为 shutdown,任务为null,并且工作队列不为空
//如果同时满足这三个要求,那么就要 处理工作队列中的任务
// 不是running状态,不处理新任务 false
//如果满足 shutdown状态,满足之前addWorker(null,false)
//并且工作队列有任务,不走false
return false;
//for 循环 开始判断数量
for (;;) {
// 获取工作线程数量
int wc = workerCountOf(c);
// 判断工作线程是否大于最大值
if (wc >= CAPACITY ||
//如果是核心 是否大于corePoolSize
// 如果是非核心线程,是否大于 最大线程数
wc >= (core ? corePoolSize : maximumPoolSize))
//当前工作线程 已经达到最大值
return false;
// cas 自增工作线程数量
if (compareAndIncrementWorkerCount(c))
// 成功跳出外出for循环,走下面的代码添加工作线程
break retry;
// cas 失败,有并发操作。
c = ctl.get(); // Re-read ctl
//基于寻获取的线程状态,判断和之前的rs状态是否一致
if (runStateOf(c) != rs)
//不一致,需要重新判断线程状态,continue 到外层for循环中
continue retry;
// 线程装填一致,在内层for 中继续 判断工作线程数量
// else CAS failed due to workerCount change; retry inner loop
}
}
//-------------
//添加工作线程,并启动工作线程
//工作线程是否启动
boolean workerStarted = false;
//工作线程是否添加
boolean workerAdded = false;
// 工作线程
Worker w = null;
try {
//构建工作线程,并将任务 扔到工作线程中
w = new Worker(firstTask);
// 拿到worker中绑定的线程
final Thread t = w.thread;
//创建工作线程成功
if (t != null) {
//加锁 线程池中已有的锁 锁定整个线程池
// 防止在添加工作线程时,其他线程执行shutdown 等方法。
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// Recheck while holding lock.
// Back out on ThreadFactory failure or if
// shut down before lock acquired.
//基于重新获取的ctl 判断线程池的状态
// 类似于双检操作, ctl状态在上面,
//在上面一段代码--没获取锁中ctl发改变 需要重新判断
int rs = runStateOf(ctl.get());
//rs<shutdown running 状态
//线程池状态为shutdown,并且传入的任务为null
//为了考虑 工作线程为0,队列中有任务
if (rs < SHUTDOWN ||
(rs == SHUTDOWN && firstTask == null)) {
//判断当前线程是否处于run状态 (健壮性判断 )
if (t.isAlive()) // precheck that t is startable
throw new IllegalThreadStateException();
// workers -》hashset
// 将构建好的worker对象添加到set中
workers.add(w);
// 当前工作线程
int s = workers.size();
//或者历史 工作线程最大值
if (s > largestPoolSize)
//线程工作线程数大于 历史最大工作线程数
largestPoolSize = s;
//完成工作线程添加,标识设置为true
workerAdded = true;
}
} finally {
///---添加工作线程数
mainLock.unlock();
}
if (workerAdded) {
//工作线程添加成功,启动线程
t.start();
//工作线程启动标识设置为true
workerStarted = true;
}
}
} finally {
//启动工作线程失败
if (! workerStarted)
// 移除set 中的work 工作线程数量-1,修改线程池状态为tidying
addWorkerFailed(w);
}
return workerStarted;
}
//启动工作线程失败后的操作
private void addWorkerFailed(Worker w) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
//判断之前创建工作线程是否成功,
if (w != null)
// 如果成功 将当前工作线程 从 set中移除
workers.remove(w);
// 对应之前cas 工作线程数+1方法 工作线程数量-1
decrementWorkerCount();
// 尝试线程池状态变为didying
tryTerminate();
} finally {
mainLock.unlock();
}
}
4.3 worker 对象
中断线程不是立即让线程停止,只是标记了thread的中断标识为true
核心内容
线程对象在里面
任务在里面 //需要执行的任务 来源1.传进来直接执行 2. 阻塞队列获取
初始化线程,不允许被中断 state=-1
private final class Worker
extends AbstractQueuedSynchronizer // 处理线程中断问题
implements Runnable //存储需要执行的任务
{
// 工作线程的thread对象,在初始化就创建了
final Thread thread;
//需要执行的任务 来源1.传进来直接执行 2. 阻塞队列获取
Runnable firstTask;
volatile long completedTasks;
Worker(Runnable firstTask) {
//当前工作线程刚刚被初始化,不允许被中断 执行runwoker
setState(-1); // inhibit interrupts until runWorker
// 任务复制
this.firstTask = firstTask;
this.thread = getThreadFactory().newThread(this);
}
//runnable 方法, 调用t.start()时,执行的run方法
public void run() {
runWorker(this);
}
protected boolean isHeldExclusively() {
return getState() != 0;
}
protected boolean tryAcquire(int unused) {
if (compareAndSetState(0, 1)) {
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
return false;
}
// 将sate 置为0 为了表示当前线程运行被中断
protected boolean tryRelease(int unused) {
setExclusiveOwnerThread(null);
setState(0);
return true;
}
public void lock() { acquire(1); }
public boolean tryLock() { return tryAcquire(1); }
public void unlock() { release(1); }
public boolean isLocked() { return isHeldExclusively(); }
void interruptIfStarted() {
Thread t;
if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
try {
t.interrupt();
} catch (SecurityException ignore) {
}
}
}
}
4.4 runworker()
//执行任务流程 中断相关
执行任务
final void runWorker(Worker w) {
//拿到当前线程 也就是worker线程
Thread wt = Thread.currentThread();
// worker对象里面的任务
Runnable task = w.firstTask;
w.firstTask = null;
//state =0
w.unlock(); // allow interrupts
// 任务执行时,钩子函数是否出异常, 出异常为true
//没出异常 变为false
boolean completedAbruptly = true;
try {
//获取任务方式1 执行execute或者submit时 直接执行
//方式2 从工作队列拿任务执行
while (task != null || (task = getTask()) != null) {
// 加锁 在shutdown状态下,当前线程不允许中断
// state 0 1
w.lock();
// 判断线程池状态 为 STOP状态,stop,那么必须将当前线程中断
//第一个判断 判断当前线程池状态是否为STOP
if ((runStateAtLeast(ctl.get(), STOP) ||
// 当前线程池不是sotp,查询当前线程是否被中断,并置为false
//如果为false,不是stop状态,
//如果为true,需要再次查看是否时并发操作导出线程池为STOP
(Thread.interrupted() &&
//查看
runStateAtLeast(ctl.get(), STOP)))
&&
// 查询当前线程是否以及被中断
!wt.isInterrupted())
//中断标志位 true
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
task = null;
// 执行成功任务个数加1
w.completedTasks++;
//state 置为0 干完活了
w.unlock();
}
}
completedAbruptly = false;
} finally {
processWorkerExit(w, completedAbruptly);
}
}
4.5 getTask()
如何从工作队列拿到任务
getTask() 从阻塞队列里拿到任务
//判断工作状态 不是shutdown等状态
//判断 工作线程数量是否大于核心线程 &&当前线程是否达到最大生存时间 && 工作线程数>! || 队列为空
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.
//、线程池状态大于等于shutdown (shutdown stop)
// 并且 . 线程池状态大于等于stop || 线程池状态为shutdown ,工作队列为空
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
//减去工作线程数量。 worker移除set集合 在processWorkerExit方法中
decrementWorkerCount();
return null;
}
//======================判断工作线程数量=======================
int wc = workerCountOf(c);
//(一般不设置 false) allowCoreThreadTimeOut允许核心超时吗(默认false) 如果true 使用keepalive 超时
// 工作线程是否大于核心线程 如果大于核心线程, 需要超时 干掉多的
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
if (
//工作线程大于最大线程
// ||(timed->ture(工作线程数大于核心线程数)&&timedOut->true( 当前线程在队列中阻塞超时))
(wc > maximumPoolSize || (timed && timedOut))
//工作线程数 >1 || 工作队列为空
&& (wc > 1 || workQueue.isEmpty())) {
// 减去当前工作线程 worker移除set集合 在processWorkerExit方法中
if (compareAndDecrementWorkerCount(c))
return null;
continue;
}
// 从工作队列中获取任务======
try {
//timed 工作线程大于核心线程
Runnable r = timed ?
// 非核心线程 阻塞救急线程存活时间,来获取任务
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
// 核心线程一直阻塞
workQueue.take();
if (r != null)
//拿到任务返回
return r;
//从队列获取任务超时,达到当前工作线程的最大生存时间
timedOut = true;
} catch (InterruptedException retry) {
timedOut = false;
}
}
}
4.6 processWorkerExit()
移除工作线程
记录移除工作线程执行多少任务
尝试改变线程池工作状态
线程池状态不是stop 状态下 :
工作队列还有值
队列有任务需要添加一个非核心线程 处理任务
/**
执行 1.当前工作线程数量达到一定程度那么返回null 在finally 执行这个
2. 当前线程池状态 不太对, 移除工作线程
*/
private void processWorkerExit(Worker w, boolean completedAbruptly) {
// 工作线程执行 钩子函数是否出异常, 出异常为true true出现中
//执行这个方法不是因为getTask返回null引起的,而是因为钩子函数 出现异常引起的
if (completedAbruptly)
//因为执行方式 “不合法” 手动扣减工作线程数
decrementWorkerCount();
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// completedTaskCount 记录当前线程池一共处理了多少任务
completedTaskCount += w.completedTasks;
//异常工作线程
workers.remove(w);
} finally {
mainLock.unlock();
}
// 尝试改变线程池状态 到过渡状态--- 销毁状态
tryTerminate();
// 获取属性
int c = ctl.get();
// 当前线程池状态 <stop 不是sto状态 (shutdown running)
if (runStateLessThan(c, STOP)) {
//(shutdown running)
if (!completedAbruptly) {
// 正常执行gettask,移除当前工作线程返回 就执行逻辑
// 核心线程数最小值 为 多少
int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
//core为0,工作队列不为空
if (min == 0 && ! workQueue.isEmpty())
//设置工作线程为1
min = 1;
//还有工作线程在线程中 就直接return
if (workerCountOf(c) >= min)
return; // replacement not needed
}
// 不正常方式移除工作线程 在添加一个,
//或者线程池工作队列不为空,且没有工作线程 也需要添加一个工作线程
addWorker(null, false);
}
}
5 线程池循环使用
第一:为什么线程池中的线程可以复用
— 是因为线程池中的线程执行的是Worker的Run方法,而这里面是一个相当于 while(true)的死循环,因此线程永远不会有执行完的那一天
第二:为什么不会被回收
— 是因为存在GC ROOT 的引用,所以无法被回收 。 引用如下
ThreadPoolExecutor -> Worker -> Thread
由于Thread 是 活着的,因此可作为GC ROOT ,所以才会看到 局部线程池ThreadPoolExecutor没有被释放