很多时候我们需要暂停线程池,而不是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()方法就能实现暂停和恢复。