线程池技术学习
线程池的工作方式
- 如果运行的线程少于 corePoolSize,则 Executor 始终首选添加新的线程,而不进行排队。什么意思?如果当前运行的线程小于corePoolSize,则任务会直接执行
- 如果运行的线程等于或多于 corePoolSize,则 Executor 始终首选将请求加入队列,而不添加新的线程。
- 如果无法将请求加入队列(队列已满),则创建新的线程,除非创建此线程超出 maximumPoolSize,如果超过,在这种情况下,新的任务将被拒绝。
生产者消费者示例
- 当生产者生产出产品时,应该通知消费者去消费。
- 当消费者消费完产品,应该通知生产者去生产。
- 当产品的库存满了的时候,生产者不应该再去生产,而是通知消费者去消费。
- 当产品的库存为0的时候,消费者不应该去消费,而是通知生产者去生产。
- 仓库类
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输出结果
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
将线程池等待队列容量调整为9
private static final ExecutorService executorService = new ThreadPoolExecutor(1, 10, 1, TimeUnit.SECONDS, new LinkedBlockingQueue<>(9));
- 测试2输出结果
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中出现了死锁,原因是工作线程只有一个,库存上限后生产者占用了工作线程一直在等待消费者,而等待队列容量过大,所以没有创建新的工作线程,导致消费任务一直在等待队列中无法被执行。