juc.ExecutorService

线程池技术学习

线程池的工作方式

  1. 如果运行的线程少于 corePoolSize,则 Executor 始终首选添加新的线程,而不进行排队。什么意思?如果当前运行的线程小于corePoolSize,则任务会直接执行
  2. 如果运行的线程等于或多于 corePoolSize,则 Executor 始终首选将请求加入队列,而不添加新的线程。
  3. 如果无法将请求加入队列(队列已满),则创建新的线程,除非创建此线程超出 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中出现了死锁,原因是工作线程只有一个,库存上限后生产者占用了工作线程一直在等待消费者,而等待队列容量过大,所以没有创建新的工作线程,导致消费任务一直在等待队列中无法被执行。

你可能感兴趣的:(juc.ExecutorService)