juc.ExecutorService

線程池技術(shù)學(xué)習(xí)

線程池的工作方式

  1. 如果運行的線程少于 corePoolSize,則 Executor 始終首選添加新的線程,而不進(jìn)行排隊。什么意思?如果當(dāng)前運行的線程小于corePoolSize,則任務(wù)會直接執(zhí)行
  2. 如果運行的線程等于或多于 corePoolSize,則 Executor 始終首選將請求加入隊列,而不添加新的線程。
  3. 如果無法將請求加入隊列(隊列已滿),則創(chuàng)建新的線程,除非創(chuàng)建此線程超出 maximumPoolSize,如果超過,在這種情況下,新的任務(wù)將被拒絕。

生產(chǎn)者消費者示例

  • 當(dāng)生產(chǎn)者生產(chǎn)出產(chǎn)品時,應(yīng)該通知消費者去消費。
  • 當(dāng)消費者消費完產(chǎn)品,應(yīng)該通知生產(chǎn)者去生產(chǎn)。
  • 當(dāng)產(chǎn)品的庫存滿了的時候,生產(chǎn)者不應(yīng)該再去生產(chǎn),而是通知消費者去消費。
  • 當(dāng)產(chǎn)品的庫存為0的時候,消費者不應(yīng)該去消費,而是通知生產(chǎn)者去生產(chǎn)。
  • 倉庫類
public class Storage {
    private int count = 0;
    private static final int MAX_COUNT = 5;

    public synchronized void produce() {
        while (count >= MAX_COUNT) {
            try {
                log.info("produce product, storage full, cannot produce!");
                wait();
            } catch (InterruptedException e) {
                log.error(e.getLocalizedMessage(), e);
            }
        }
        count++;
        log.info("produce product, storage:{}", count);
        // produce complete, notify one consumer who may be waiting for
        this.notify();
    }

    public synchronized void consume() {
        while (count == 0) {
            try {
                log.info("consume product, storage empty, cannot consume!");
                wait();
            } catch (InterruptedException e) {
                log.error(e.getLocalizedMessage(), e);
            }
        }
        count--;
        log.info("consume product, storage:{}", count);
        // consume complete, notify one producer who may be waiting for
        this.notify();
    }
}
  • 測試1
    線程池等待隊列容量為2
private static final ExecutorService executorService = new ThreadPoolExecutor(1, 10, 1, TimeUnit.SECONDS, new LinkedBlockingQueue<>(2));
//    private static final ExecutorService executorService = Executors.newCachedThreadPool();

    public static void main(String[] args) {
        Storage storage = new Storage();
        // 5 producer
        for (int i = 0; i < 5; i++) {
            executorService.execute(() -> {
                while (true) {
                    storage.produce();
                }
            });
        }
        // 5 consumer
        for (int i = 0; i < 5; i++) {
            executorService.execute(() -> {
                while (true) {
                    storage.consume();
                }
            });
        }
        executorService.shutdown();
    }
  • 測試1輸出結(jié)果
14:41:50.586 [pool-1-thread-1] INFO org.rrycho.ikaros.domain.Storage - produce product, storage:1
14:41:50.586 [pool-1-thread-1] INFO org.rrycho.ikaros.domain.Storage - produce product, storage:2
14:41:50.586 [pool-1-thread-1] INFO org.rrycho.ikaros.domain.Storage - produce product, storage:3
14:41:50.586 [pool-1-thread-1] INFO org.rrycho.ikaros.domain.Storage - produce product, storage:4
14:41:50.586 [pool-1-thread-1] INFO org.rrycho.ikaros.domain.Storage - produce product, storage:5
14:41:50.586 [pool-1-thread-1] INFO org.rrycho.ikaros.domain.Storage - produce product, storage full, cannot produce!
14:41:50.586 [pool-1-thread-6] INFO org.rrycho.ikaros.domain.Storage - consume product, storage:4
14:41:50.586 [pool-1-thread-6] INFO org.rrycho.ikaros.domain.Storage - consume product, storage:3
14:41:50.586 [pool-1-thread-6] INFO org.rrycho.ikaros.domain.Storage - consume product, storage:2
14:41:50.586 [pool-1-thread-6] INFO org.rrycho.ikaros.domain.Storage - consume product, storage:1
14:41:50.586 [pool-1-thread-6] INFO org.rrycho.ikaros.domain.Storage - consume product, storage:0
14:41:50.586 [pool-1-thread-6] INFO org.rrycho.ikaros.domain.Storage - consume product, storage empty, cannot consume!
14:41:50.586 [pool-1-thread-4] INFO org.rrycho.ikaros.domain.Storage - consume product, storage empty, cannot consume!
14:41:50.586 [pool-1-thread-2] INFO org.rrycho.ikaros.domain.Storage - produce product, storage:1
14:41:50.586 [pool-1-thread-2] INFO org.rrycho.ikaros.domain.Storage - produce product, storage:2
14:41:50.586 [pool-1-thread-2] INFO org.rrycho.ikaros.domain.Storage - produce product, storage:3
14:41:50.586 [pool-1-thread-2] INFO org.rrycho.ikaros.domain.Storage - produce product, storage:4
14:41:50.586 [pool-1-thread-2] INFO org.rrycho.ikaros.domain.Storage - produce product, storage:5
14:41:50.586 [pool-1-thread-2] INFO org.rrycho.ikaros.domain.Storage - produce product, storage full, cannot produce!
14:41:50.586 [pool-1-thread-3] INFO org.rrycho.ikaros.domain.Storage - produce product, storage full, cannot produce!
  • 測試2
    將線程池等待隊列容量調(diào)整為9
private static final ExecutorService executorService = new ThreadPoolExecutor(1, 10, 1, TimeUnit.SECONDS, new LinkedBlockingQueue<>(9));
  • 測試2輸出結(jié)果
14:45:31.373 [pool-1-thread-1] INFO org.rrycho.ikaros.domain.Storage - produce product, storage:1
14:45:31.378 [pool-1-thread-1] INFO org.rrycho.ikaros.domain.Storage - produce product, storage:2
14:45:31.378 [pool-1-thread-1] INFO org.rrycho.ikaros.domain.Storage - produce product, storage:3
14:45:31.378 [pool-1-thread-1] INFO org.rrycho.ikaros.domain.Storage - produce product, storage:4
14:45:31.378 [pool-1-thread-1] INFO org.rrycho.ikaros.domain.Storage - produce product, storage:5
14:45:31.378 [pool-1-thread-1] INFO org.rrycho.ikaros.domain.Storage - produce product, storage full, cannot produce!

可以看到測試2中出現(xiàn)了死鎖,原因是工作線程只有一個,庫存上限后生產(chǎn)者占用了工作線程一直在等待消費者,而等待隊列容量過大,所以沒有創(chuàng)建新的工作線程,導(dǎo)致消費任務(wù)一直在等待隊列中無法被執(zhí)行。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容