【線程池】線程池的鉤子方法與使用示例

在每個任務執行前後使用鉤子方法可以實現一些線程池輔助功能,例如線程池的暫停與恢復、打印日誌、統計等。

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("線程池恢復執行");
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章