【线程池】线程池的钩子方法与使用示例

在每个任务执行前后使用钩子方法可以实现一些线程池辅助功能,例如线程池的暂停与恢复、打印日志、统计等。

ThreadPoolExecutor提供了3个钩子方法,需要子类根据需要重写方法。对于三个钩子方法的使用,参见runWoker方法和tryTerminate方法。

protected void beforeExecute(Thread t, Runnable r) { } // 任务执行前
protected void afterExecute(Runnable r, Throwable t) { } // 任务执行后
protected void terminated() { } // 线程池执行结束后

示例:使用beforeExecute()辅助实现线程池的暂停与恢复

public class PauseableThreadPool extends ThreadPoolExecutor {
    /**
     * 显式锁
     */
    private final ReentrantLock lock = new ReentrantLock();

    private Condition unpaused = lock.newCondition();

    private boolean isPaused;

    public PauseableThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
    }

    /**
     * 每个任务执行前执行,识别标记位
     *
     * @param t
     * @param r
     */
    @Override
    protected void beforeExecute(Thread t, Runnable r) {
        super.beforeExecute(t, r);
        lock.lock();
        try {
            while (isPaused) {
                unpaused.await(); // 阻塞挂起,释放锁
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    // 暂停与恢复
    private void pause() {
        lock.lock();
        try {
            isPaused = true;
        } finally {
            lock.unlock();
        }
    }

    private void resume() {
        lock.lock();
        try {
            isPaused = false;
            unpaused.signalAll(); // 通知唤醒
        } finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        PauseableThreadPool pool = new PauseableThreadPool(10, 20, 100, TimeUnit.SECONDS, new LinkedBlockingDeque<>());
        Runnable task = () -> {
            System.out.println("任务被执行" + Thread.currentThread().getName());
            try {
                TimeUnit.MILLISECONDS.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        };
        for (int i = 0; i < 10000; i++) {
            pool.execute(task);
        }
        TimeUnit.SECONDS.sleep(1);
        pool.pause();
        System.out.println("线程池暂停");
        TimeUnit.SECONDS.sleep(10);
        pool.resume();
        System.out.println("线程池恢复执行");
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章