美文网首页
juc.ExecutorService

juc.ExecutorService

作者: Kitsuna | 来源:发表于2020-06-23 23:56 被阅读0次

    线程池技术学习

    线程池的工作方式

    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

          本文链接:https://www.haomeiwen.com/subject/jhscwqtx.html