很多时候我们需要暂停线程池,而不是shutdown线程池,暂停线程池可以为我们保存任务,稍后可以继续执行,从而避免不必要的开销。
这里我提供一种暂停线程池的方法;
首先拿到ThreadPoolExecutor.java源码,将其变为自己包内的私有类;
接下来修改线程池,
先在线程池类中添加一下方法和变量:
BlockingQueue<Runnable> pauseQueue=new ArrayBlockingQueue<>(1);//暂停时用来则塞线程的空任务队列
isPause=true;//暂停
public void pause(){//暂停线程池,但是仍然接受任务
isPause=true;
System.out.println("暂停了"+isPause+exit);
}
public void resume(){//恢复线程池,开始接着执行任务
isPause=false;
if (workQueue.isEmpty()) {
return;
}
pauseQueue.offer(workQueue.poll());
}
然后修改以下方法:
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);
if (isPause){
try {
return pauseQueue.take();
} catch (InterruptedException e) {
}
}
// Are workers subject to culling?
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
if ((wc > maximumPoolSize || (timed && timedOut))
&& (wc > 1 ||workQueue.isEmpty())) {
if (compareAndDecrementWorkerCount(c)) {
return null;
}
continue;
}
try {
Runnable r = timed ?// TODO: 2017/5/14 keepAliveTime为空闲线程存活的时间
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :// TODO: 2017/5/14 在空闲线程关闭之前尝试取走队列头的任务,如果还没有任务则返回null
workQueue.take();// TODO: 2017/5/14 获取队列头的任务 然后 在从队列移除该任务;
if (r != null) {
return r;
}
timedOut = true;// TODO: 2017/5/14 如果取不到任务则循环重取,如果队列已空则在上面返回空,当返回空时代表所有任务已完成,那么工作机器人会关闭并销毁
} catch (InterruptedException retry) {
timedOut = false;
}
}
}
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
if (isPause) { if (!workQueue.offer(command)) reject(command); return; }
/* * 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. */ int c = ctl.get(); if (workerCountOf(c) < corePoolSize) { 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); else if (workerCountOf(recheck) == 0) addWorker(null, false); } else if (!addWorker( command, false)) reject(command);} OK,先在只要调用pause()和resume()方法就能实现暂停和恢复。