• java阻塞队列之LinkedBlockingQueue


    概述

    LinkedBlockingQueue内部由单链表实现,只能从head取元素,从tail添加元素。添加元素和获取元素都有独立的锁,也就是说LinkedBlockingQueue是读写分离的,读写操作可以并行执行。LinkedBlockingQueue采用可重入锁ReentrantLock来保证在并发情况下的线程安全。

    构造器

    LinkedBlockingQueue一共有三个构造器,分别是无参构造器、可以指定容量的构造器、可以穿入一个容器的构造器。如果在创建实例的时候调用的是无参构造器,LinkedBlockingQueue的默认容量是Integer.MAX_VALUE,这样做很可能会导致队列还没有满,但是内存却已经满了的情况(内存溢出)。

    public LinkedBlockingQueue();   //设置容量为Integer.MAX
    public LinkedBlockingQueue(int capacity);  //设置指定容量
    public LinkedBlockingQueue(Collection<? extends E> c);  //穿入一个容器,如果调用该构造器,容量默认也是Integer.MAX_VALUE
    

    LinkedBlockingQueue常用操作

    取数据

    take():首选。当队列为空时阻塞

    poll():弹出队顶元素,队列为空时,返回空

    peek():和poll烈性,返回队队顶元素,但顶元素不弹出。队列为空时返回null

    remove(Object o):移除某个元素,队列为空时抛出异常。成功移除返回true

    添加数据

    put():首选。队满是阻塞

    offer():队满时返回false

    判断队列是否为空

    size()方法会遍历整个队列,时间复杂度为O(n),所以最好选用isEmtpy

    put元素原理

    基本过程:

    1.判断元素是否为null,为null抛出异常

    2.加锁(可中断锁)

    3.判断队列长度是否到达容量,如果到达一直等待

    4.如果没有队满,enqueue()在队尾加入元素

    5.队列长度加1,此时如果队列还没有满,调用signal唤醒其他堵塞队列

    if (e == null) throw new NullPointerException();
    
            int c = -1;
            Node<E> node = new Node<E>(e);
            final ReentrantLock putLock = this.putLock;
            final AtomicInteger count = this.count;
            putLock.lockInterruptibly();
            try {
                while (count.get() == capacity) {
                    notFull.await();
                }
                enqueue(node);
                c = count.getAndIncrement();
                if (c + 1 < capacity)
                    notFull.signal();
            } finally {
                putLock.unlock();
            }
    

    take元素原理

    基本过程:

    1.加锁(依旧是ReentrantLock),注意这里的锁和写入是不同的两把锁

    2.判断队列是否为空,如果为空就一直等待

    3.通过dequeue方法取得数据

    3.取走元素后队列是否为空,如果不为空唤醒其他等待中的队列

    public E take() throws InterruptedException {
            E x;
            int c = -1;
            final AtomicInteger count = this.count;
            final ReentrantLock takeLock = this.takeLock;
            takeLock.lockInterruptibly();
            try {
                while (count.get() == 0) {
                    notEmpty.await();
                }
                x = dequeue();
                c = count.getAndDecrement();
                if (c > 1)
                    notEmpty.signal();
            } finally {
                takeLock.unlock();
            }
            if (c == capacity)
                signalNotFull();
            return x;
        }
    

    enqueue()和dequeue()方法实现都比较简单,无非就是将元素添加到队尾,从队顶取走元素,感兴趣的朋友可以自己去看一下,这里就不粘贴了。

  • 相关阅读:
    【Ecstore2.0】计划任务/队列/导入导出 的执行问题
    【Ecstore2.0】第三方信任登陆问题解决_备忘
    Ecstore 2.0 报表显示空白
    【Linux】 任务调度/计划 cron
    wdcp/wdlinux一键包的php5.3版本添加Zend.so 和Soap.so
    wdcp/wdlinux 在 UBUNTU/linux 中安装失败原因之创建用户
    假如女人是一种编程语言,你会更喜欢哪一种
    Linux中的ln
    wdcp/wdlinux 常用工具及命令集
    php 数组Array 删除指定键名值
  • 原文地址:https://www.cnblogs.com/dongye95/p/16043035.html
Copyright © 2020-2023  润新知