如何写一个可暂停的线程池

381 阅读1分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

假如我们当前有一个需求,要求线程池可以控制暂停恢复,我们该如何做呢?

线程池提供了 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...