小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
假如我们当前有一个需求,要求线程池可以控制暂停恢复,我们该如何做呢?
线程池提供了 beforeExecute方法,可以用来在执行线程任务之前进行一些操作,比如阻塞当前线程,中断线程,因此,我们可以利用线程池的这个方法(可以视为钩子函数)来实现可暂停的线程池。
实现源码
package org.example.concurrent;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author Catch
*/
public class PauseableThreadPool extends ThreadPoolExecutor {
public PauseableThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
}
// 设置一个暂停标志
private boolean isPaused;
// 为了支持并发修改 isPaused, 需要一把锁
private final ReentrantLock lock=new ReentrantLock();
// 需要一个 lock 的条件
private final Condition condition = lock.newCondition();
@Override
protected void beforeExecute(Thread t, Runnable r) {
super.beforeExecute(t, r);
lock.lock();
try {
// 循环检查是否被暂停,暂停了就 await
while (isPaused) {
condition.await();
}
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
/**
* 暂停
*/
public void pause(){
lock.lock();
try {
isPaused = true;
}finally {
lock.unlock();
}
}
/**
* 恢复
*/
public void resume(){
lock.lock();
try {
isPaused=false;
condition.signalAll();
}finally {
lock.unlock();
}
}
public static void main(String[] args) throws InterruptedException {
PauseableThreadPool pool = new PauseableThreadPool(10, 10, 10L, TimeUnit.SECONDS, new LinkedBlockingQueue<>());
Runnable runnable = () -> {
System.out.println("running...");
try {
Thread.sleep(100L);
} catch (InterruptedException e) {
e.printStackTrace();
}
};
for (int i = 0; i < 10000; i++) {
pool.execute(runnable);
}
Thread.sleep(1500L);
pool.pause();
System.out.println("pause**************************************");
Thread.sleep(3000L);
pool.resume();
System.out.println("resume=====================================");
}
}
通过运行 main 方法可以看到线程再运行一段时间后被暂停然后又恢复运行:
running...
running...
running...
running...
running...
running...
running...
pause**************************************
resume=====================================
running...
running...
running...
running...