前言
今天看了下雄哥的Java如何让线程池满后再放队列,虽然说看完实现有点骚,但是感叹到我,这招曲线救国很强。
ThreadPookExecutor部分源码
execute(Runnable command)
看下下面中文注释
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();
//线程数小于核心线程数,就是新建线程,丢到线程池里面addWorker().然后里面会对计数进行+1
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
//如果线程池还在跑,尝试丢到队列里头,通过判断offer方法来判断是否队列已经满了,这个也是为啥无界队列会导致cpu爆的原因,一直往队列插入。
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);
}
//如果到达最大线程数的话,会抛出异常RejectedExecutionException
else if (!addWorker(command, false))
reject(command);
}
RejectedExecutionException是不是有点熟悉,当任务太多的时候,线程池会抛出这个异常也可以理解为线程池的拒绝策略。
观后感
看了雄哥的那篇博客,是先达到最大线程数再往队列里头插~
我们来看下是怎么实现的
重写线程池
public class EagerThreadPoolExecutor extends ThreadPoolExecutor {
/**
* 定义一个成员变量,用于记录当前线程池中已提交的任务数量
*/
private final AtomicInteger submittedTaskCount = new AtomicInteger(0);
public EagerThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit, TaskQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);
}
public int getSubmittedTaskCount() {
return submittedTaskCount.get();
}
@Override
protected void afterExecute(Runnable r, Throwable t) {
// ThreadPoolExecutor的勾子方法,在task执行完后需要将池中已提交的任务数 - 1
submittedTaskCount.decrementAndGet();
}
@Override
public void execute(Runnable command) {
if (command == null) {
throw new NullPointerException();
}
// do not increment in method beforeExecute!
// 将池中已提交的任务数 + 1
submittedTaskCount.incrementAndGet();
try {
super.execute(command);
} catch (RejectedExecutionException rx) {
// retry to offer the task into queue.
final TaskQueue queue = (TaskQueue) super.getQueue();
try {
if (!queue.retryOffer(command, 0, TimeUnit.MILLISECONDS)) {
submittedTaskCount.decrementAndGet();
throw new RejectedExecutionException("Queue capacity is full.", rx);
}
} catch (InterruptedException x) {
submittedTaskCount.decrementAndGet();
throw new RejectedExecutionException(x);
}
} catch (Throwable t) {
// decrease any way
submittedTaskCount.decrementAndGet();
throw t;
}
}
}
主要代码
super.execute(command);这就是曲线救国的方法,通过执行原线程池的执行方法,那么之前ThreadPoolExecute的执行顺序怎么办?
这里涉及上面源码解读里头的workQueue.offer(command),如果它为false的时候,表示插入不了,那么在在线程数超过核心线程数,没有超过最大数量时,会抛出RejectedExecutionException异常。
那么雄哥的实现是捕获异常,塞到队列里头。当它为false的时候,表示队列也满了,抛出RejectedExecutionException异常。
我感觉这操作很骚,但是又很强,哈哈,牛逼牛逼~
那么这里涉及队列的offer返回false的操作(看上面加粗的字的解释,为啥需要返回false)
重写队列
public class TaskQueue<R extends Runnable> extends LinkedBlockingQueue<Runnable> {
private static final long serialVersionUID = -2635853580887179627L;
// 自定义的线程池类,继承自ThreadPoolExecutor
private EagerThreadPoolExecutor executor;
public TaskQueue(int capacity) {
super(capacity);
}
public void setExecutor(EagerThreadPoolExecutor exec) {
executor = exec;
}
// offer方法的含义是:将任务提交到队列中,返回值为true/false,分别代表提交成功/提交失败
@Override
public boolean offer(Runnable runnable) {
if (executor == null) {
throw new RejectedExecutionException("The task queue does not have executor!");
}
// 线程池的当前线程数
int currentPoolThreadSize = executor.getPoolSize();
if (executor.getSubmittedTaskCount() < currentPoolThreadSize) {
// 已提交的任务数量小于当前线程数,意味着线程池中有空闲线程,直接扔进队列里,让线程去处理
return super.offer(runnable);
}
// return false to let executor create new worker.
if (currentPoolThreadSize < executor.getMaximumPoolSize()) {
// 重点: 当前线程数小于 最大线程数 ,返回false,暗含入队失败,让线程池去创建新的线程
return false;
}
// 重点: 代码运行到此处,说明当前线程数 >= 最大线程数,需要真正的提交到队列中
return super.offer(runnable);
}
public boolean retryOffer(Runnable o, long timeout, TimeUnit unit) throws InterruptedException {
if (executor.isShutdown()) {
throw new RejectedExecutionException("Executor is shutdown!");
}
return super.offer(o, timeout, unit);
}
}
重点代码
// return false to let executor create new worker.
if (currentPoolThreadSize < executor.getMaximumPoolSize()) {
// 重点: 当前线程数小于 最大线程数 ,返回false,暗含入队失败,让线程池去创建新的线程
return false;
}