• 9、阻塞队列


    引用学习(狂神说)

    什么情况下我们会使用 阻塞队列:多线程并发处理,线程池的管理!

    队列的阻塞和家族介绍

    队列的阻塞

    队列遵循先进先出(FIFO)的原则。

    这FIFO是单词的缩写,对应First Input First Ouput

    家族成员

    首先是要讲的阻塞队列

    对应的API文档:介绍了如下的实现类

    父接口Queue<E>

    家族的成员

     家族的成员:树形图

     所以说:BlockingQueue 不是新的东西,只是你没有接触到,它和List、Set容器的实现类都是同级的关系。

    学会使用BlockingQueue队列

    实现类:ArrayBlockingQueue 非阻塞队列

    需要掌握的就是:队列的添加、移除操作。

    添加和移除的操作对应了4组API(4组添加和移除的操作,会产生以下的效果):

    1、会抛出异常

    2、不会抛出异常,但是有返回值

    3、阻塞、等待

    4、超时等待

    方法抛出异常不抛出异常,有返回值阻塞、等待超时等待
    添加 add() offer() put() offer(E e, long timeout, TimeUnit unit)
    移除 remove() poll() take() poll(long timeout, TimeUnit unit)
    检查队首元素 element() peek() - -

    抛出异常的方法

    package com.zxh.blockingQueue;
    
    import java.util.concurrent.ArrayBlockingQueue;
    
    public class Test {
        public static void main(String[] args) {
            test1();
        }
        /**
         * 抛出异常
         */
        public static void test1(){
            // 初始化队列的大小为3
            ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue<>(3);
    
            // 添加方法,添加成功返回true
            System.out.println(blockingQueue.add("a"));
            System.out.println(blockingQueue.add("b"));
            System.out.println(blockingQueue.add("c"));
            System.out.println(blockingQueue.element());    // 检查队首元素
    //        java.lang.IllegalStateException: Queue full:非法状态异常:队列已满
    //        System.out.println(blockingQueue.add("d"));
    
            System.out.println(blockingQueue.remove());
            System.out.println(blockingQueue.remove());
            System.out.println(blockingQueue.remove());
    //        java.util.NoSuchElementException:没有可删除的值,抛出异常
    //        System.out.println(blockingQueue.remove());
    
        }
    }

     队列已满的情况下添加:

     没有值的情况下删除:

    不抛出异常的方法

    package com.zxh.blockingQueue;
    
    import java.util.concurrent.ArrayBlockingQueue;
    
    public class Test {
        public static void main(String[] args) {
            test2();
        }
        
        /**
         * 不抛出异常,有返回值
         */
        public static void test2(){
            ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue<>(3);
    
            // 添加方法,添加成功返回true
            System.out.println(blockingQueue.offer("a"));
            System.out.println(blockingQueue.offer("b"));
            System.out.println(blockingQueue.offer("c"));
            System.out.println(blockingQueue.peek());   // 检查队首元素
    //        System.out.println(blockingQueue.offer("d"));   // false,队列已满,添加失败返回false
    
            System.out.println(blockingQueue.poll());
            System.out.println(blockingQueue.poll());
            System.out.println(blockingQueue.poll());
    //        System.out.println(blockingQueue.poll());   // 队列为空,删除失败返回 null
    
        }
    }

     队列已满的情况下添加:

     没有值的情况下删除:

    阻塞、等待的方法

    package com.zxh.blockingQueue;
    
    import java.util.concurrent.ArrayBlockingQueue;
    
    public class Test {
        public static void main(String[] args) throws InterruptedException {
            test3();
        }
    
        /**
         * 阻塞、等待
         */
        public static void test3() throws InterruptedException {
            ArrayBlockingQueue<Object> blockingQueue = new ArrayBlockingQueue<>(3);
    
            // 添加方法
            blockingQueue.put("a");
            blockingQueue.put("b");
            blockingQueue.put("c");
    //        blockingQueue.put("d"); //如果队列已满,再次添加会一直等待有元素移除,就会造成阻塞
    
            // 移除方法
            System.out.println(blockingQueue.take());
            System.out.println(blockingQueue.take());
            System.out.println(blockingQueue.take());
    //        System.out.println(blockingQueue.take());   //如果队列为空,再次移除会一直等待新的元素加入,就会造成阻塞
    
        }
    
    }

     队列已满的情况下添加:

     没有值的情况下删除:

     

    超时等待的方法

    package com.zxh.blockingQueue;
    
    import java.util.concurrent.ArrayBlockingQueue;
    
    public class Test {
        public static void main(String[] args) throws InterruptedException {
            test4();
        }
    
        /**
         * 超时等待
         */
        public static void test4() throws InterruptedException {
            ArrayBlockingQueue<Object> blockingQueue = new ArrayBlockingQueue<>(3);
    
            // 添加方法
            System.out.println(blockingQueue.offer("a"));
            System.out.println(blockingQueue.offer("b"));
            System.out.println(blockingQueue.offer("c"));
    //        offer(E e, long timeout, TimeUnit unit):e表示要添加的值,timeout等待时间,unit延迟类型
    //        如果队列已满,等待2s后,终止程序,返回false
    //        System.out.println(blockingQueue.offer("d", 2, TimeUnit.SECONDS));
    
            System.out.println(blockingQueue.poll());
            System.out.println(blockingQueue.poll());
            System.out.println(blockingQueue.poll());
    //        poll(long timeout, TimeUnit unit):timeout等待时间, unit延迟类型
    //        如果队里为空,再次删除会等待2s,终止程序,返回null
    //        System.out.println(blockingQueue.poll(2, TimeUnit.SECONDS));
    
    
        }
    
    }

     队列已满的情况下添加:等待2s终止程序,返回false

     没有值的情况下删除:会等待2s,终止程序,返回null

    实现类:SynchronousQueue 同步队列

    同步队列SynchronousQueue

    • 1、不存储元素

    • 2、同步操作,存储一个元素后,必须要拿出来,才能再往里面存储

    • 3、当存储一个元素后,再存储元素,就会阻塞,因为需要等待元素的取出

    测试同时存储2个元素的情况

    public class SynchronousQueueTest {
        public static void main(String[] args) {
            BlockingQueue<String> blockingQueue = new SynchronousQueue<>();
    
            try {
                blockingQueue.put("A");
                blockingQueue.put("B"); // 无法再次存储,队列会阻塞,同步队列只能存再取
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
        }
    }

    就会一直等待取出

     测试多个线程存取

    • 结果:每一次存储后,都会等待取出之后,才会再次存储。
    package com.zxh.blockingQueue;
    
    import java.util.concurrent.BlockingQueue;
    import java.util.concurrent.SynchronousQueue;
    import java.util.concurrent.TimeUnit;
    
    /**
     * 同步队列SynchronousQueue
     * 1、不存储元素
     * 2、同步操作,存储一个元素后,必须要拿出来,才能再往里面存储
     * 3、当存储一个元素后,再存储元素,就会阻塞,因为需要等待元素的取出
     *
     */
    public class SynchronousQueueTest {
        public static void main(String[] args) {
            BlockingQueue<String> blockingQueue = new SynchronousQueue<>();
    
            new Thread(()->{
                try {
                    System.out.println(Thread.currentThread().getName() + "=> put 1");
                    blockingQueue.put("1");
                    System.out.println(Thread.currentThread().getName() + "=> put 2");
                    blockingQueue.put("2");
                    System.out.println(Thread.currentThread().getName() + "=> put 3");
                    blockingQueue.put("3");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }, "T1").start();
            new Thread(()->{
                try {
                    TimeUnit.SECONDS.sleep(2);
                    System.out.println(Thread.currentThread().getName() + "=> get 1");
                    blockingQueue.take();
                    TimeUnit.SECONDS.sleep(2);
                    System.out.println(Thread.currentThread().getName() + "=> get 2");
                    blockingQueue.take();
                    TimeUnit.SECONDS.sleep(2);
                    System.out.println(Thread.currentThread().getName() + "=> get 3");
                    blockingQueue.take();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }, "T2").start();
    
        }
    }

    先存再取,同步操作

    致力于记录学习过程中的笔记,希望大家有所帮助(*^▽^*)!
  • 相关阅读:
    腾讯云大数据套件Hermes-MR索引插件使用总结
    【文智背后的奥秘】系列篇——文本聚类系统
    【文智背后的奥秘】系列篇——关键词智能提取
    微信Tinker的一切都在这里,包括源码(一)
    腾讯云CMQ消息队列在Windows环境下的使用
    树莓派使用modbus与stm32通信
    Ubuntu manjaro 17.10 UTC
    如何彻底禁止360浏览器弹窗
    CentOS DesktopEntry
    centos7 安装qt
  • 原文地址:https://www.cnblogs.com/zxhbk/p/12960996.html
Copyright © 2020-2023  润新知