BlockingQueue之ArrayBlockingQueue、LinkedBlockingQueue、BlockingDeque之LinkedBlockingDeque

BlockingQueue

    BlockingQueue即阻塞队列,它的特点就是阻塞添加和阻塞删除。

  • 阻塞添加:当阻塞队列元素已满时,队列会阻塞加入元素的线程,直到队列元素不满时才唤醒线程执行元素加入操作。
  • 阻塞删除:指在队列元素为空时,删除队列元素的线程将被阻塞,直到队列不为空再执行。

添加

  • add():普通添加方法,如果队列已经满了会抛出异常。
  • offer():如果队列满了,返回false;也可以使用重载方法设置等待时间。
  • put():如果队列满了,就阻塞,直到线程被中断或者被唤醒

删除

  • remove():普通删除方法,如果队列为空会抛出异常。
  • poll():如果队列没有元素,直接返回null;也可以使用重载方法设置等待时间。
  • take():如果队列没有元素,就阻塞,直到线程被中断或者被唤醒

获得队首元素

  • element():普通方法,为空的时候会抛出异常。
  • peek():为空的时候返回null。

ArrayBlockingQueue

    ArrayBlockingQueue是使用数组实现的队列,并且在构造ArrayBlockingQueue时需要指定容量,也就意味着底层数组一旦创建了,容量就不能改变了,因此它是一个由基于数组的有界阻塞队列。

  • 不允许元素为null(AbstractQueue类不允许由null元素)
  • 入队和出队是都有lock保证同步
public class ArrayBlockingQueue<E> extends AbstractQueue<E>
        implements BlockingQueue<E>, java.io.Serializable {
    final Object[] items;
    //下个要删除的项的索引
    int takeIndex;
    //下个插入的位置
    int putIndex;
    //元素数量
    int count;
    //全局锁,默认会使用非公平锁。
    final ReentrantLock lock;
    //Condition for waiting takes
    private final Condition notEmpty;
    //Condition for waiting puts
    private final Condition notFull;
}

LinkedBlockingQueue

    LinkedBlockingQueue是一个基于单向链表的可指定大小的阻塞队列。新的元素将会被插入到队列的尾部,队头的元素是插入时间最长的,队尾的元素是最新插入的。LinkedBlockingQueue的容量限制是可选的,如果在初始化时没有指定容量,那么默认使用int的最大值作为队列容量。
    LinkedBlockingQueue中有两把锁,一把锁用于入队,一把锁用于出队,这也就意味着,同一时刻只能有一个线程执行入队或者出队,其余执行入队或者出队的线程将会被阻塞。但是如果同时有两个线程在操作队列一个入队线程和一个出队,为了维持线程安全,LinkedBlockingQueue使用一个AtomicInterger类型的变量表示当前队列中含有的元素个数,以确保两个线程之间操作底层队列是线程安全的。

  • remove方法需要对2个锁同时加锁。
  • 不允许元素为null
public class LinkedBlockingDeque<E>
        extends AbstractQueue<E>
        implements BlockingDeque<E>, java.io.Serializable {
    //用于存储数据
    static class Node<E> {
        E item;
        Node<E> next;
    }

    //阻塞队列的大小,默认为Integer.MAX_VALUE
    private final int capacity;
    // 当前阻塞队列中的元素个数 
    private final AtomicInteger count = new AtomicInteger();
    //取出数据时,都是从表头head处获取
    transient Node<E> head;
    //新增数据时,都是从表尾last处插入
    private transient Node<E> last;

    // 获取并移除元素时使用的锁,如take, poll, etc 
    private final ReentrantLock takeLock = new ReentrantLock();
    // notEmpty条件对象,当队列没有数据时用于挂起执行删除的线程 
    private final Condition notEmpty = takeLock.newCondition();

    // 添加元素时使用的锁如 put, offer, etc 
    private final ReentrantLock putLock = new ReentrantLock();
    // notFull条件对象,当队列数据已满时用于挂起执行添加的线程 
    private final Condition notFull = putLock.newCondition();
}

两者的区别

ArrayBlockingQueue

  • 一个对象数组、一把锁、两个条件
  • 在只有入队高并发或出队高并发的情况下,操作数组不需要扩容,性能很高
  • 采用了数组,必须指定大小,容量有限

LinkedBlockingQueue:

  • 一个单向链表、两把锁、两个条件
  • 两把锁,避免了入队与出队时使用一把锁带来的竞争
  • 在入队与出队都高并发的情况下,性能比ArrayBlockingQueue高很多
  • 采用了链表,最大容量为整数最大值,可看做容量无限

BlockingDeque

    deque是“Double Ended Queue”(双端队列)的缩写,BlockingDeque表示一个双向队列。线程将生成元素并将它们插入队列的任一端,如果deque当前已满,则插入线程将被阻塞,直到删除线程将元素从双端队列中取出;如果deque当前为空,则将阻止删除线程,直到插入线程将元素插入到双端队列中。
    BlockingDeque是BlockingQueue的子类。

BlockingQueueBlockingDeque
add()addFirst() / addLast()
offer() 分为无参和带参数两种offerXxst() x 2
put()putXxst()
remove()removeXxst()
poll() x 2pollXxst() x 2
take()takeXxst()
element()getXxst()
peek()peekXxst()

LinkedBlockingDeque

    LinkedBlockingDeque是一个基于双向链表的可指定大小的双端阻塞队列,该阻塞队列和LinkedBlockingQueue类似只是同时支持FIFO和FILO两种操作方式。
    因为队列能够同时进行入队和出队操作,所以需要将两个锁同时加锁才能保证操作的同步性,性能自然不如只使用一个锁的好。

  • 若消费线程要取出数据时,队列正好为空,则该线程会执行notEmpty.await()进行等待;当其它生产线程向队列中插入了数据之后,会调用notEmpty.signal()唤醒“notEmpty上的等待线程”,此时消费线程会被唤醒从而得以继续运行。 当消费线程在执行取操作前,会获取takeLock,在取操作执行完毕再释放takeLock。
  • 若生产线程要插入数据时,队列已满,则该线程会它执行notFull.await()进行等待;当其它消费线程取出数据之后,会调用notFull.signal()唤醒“notFull上的等待线程”,此时生产线程就会被唤醒从而得以继续运行。当生产线程在执行插入操作前,会获取putLock,在插入操作执行完毕才释放putLock。
public class LinkedBlockingDeque<E>
        extends AbstractQueue<E>
        implements BlockingDeque<E>, java.io.Serializable {
    static final class Node<E> {
        E item;
        Node<E> prev;
        Node<E> next;
    }
    transient Node<E> first;
    transient Node<E> last;
    private transient int count;
    private final int capacity;
    final ReentrantLock lock = new ReentrantLock();
    private final Condition notEmpty = lock.newCondition();
    private final Condition notFull = lock.newCondition();
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值