線程池技術(shù)學(xué)習(xí)
線程池的工作方式
- 如果運行的線程少于 corePoolSize,則 Executor 始終首選添加新的線程,而不進(jìn)行排隊。什么意思?如果當(dāng)前運行的線程小于corePoolSize,則任務(wù)會直接執(zhí)行
- 如果運行的線程等于或多于 corePoolSize,則 Executor 始終首選將請求加入隊列,而不添加新的線程。
- 如果無法將請求加入隊列(隊列已滿),則創(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í)行。