05.JUC 集合
来源:互联网 发布:新编诸子集成知乎 编辑:程序博客网 时间:2024/06/05 00:15
基本概念
LinkedBlockingQueue 是一个用链表实现的有界阻塞队列。
LinkedBlockingQueue 按照先进先出的原则对元素进行排序。
LinkedBlockingQueue 采用了双锁、双条件队列来提高读写效率。
内部构造
LinkedBlockingQueue 内部维护着一个单向链表,且链表头节点的值永远为空。如下图所示:
下面来看它的构成:
- Node ,节点
static class Node<E> { E item; Node<E> next; Node(E x) { item = x; }}
- 构造函数
private transient Node<E> head;private transient Node<E> last;private final int capacity;public LinkedBlockingQueue() { // 该队列是有界的,若不指定容量,默认为最大值 this(Integer.MAX_VALUE);}public LinkedBlockingQueue(int capacity) { if (capacity <= 0){ // 抛出异常... } this.capacity = capacity; last = head = new Node<E>(null);}
双锁机制
由于采用了双锁机制,因此它的出队、入队操作可以同时进行,从而提高效率。
// 用于入队操作private final ReentrantLock putLock = new ReentrantLock();private final Condition notFull = putLock.newCondition();// 用于出队操作private final ReentrantLock takeLock = new ReentrantLock();private final Condition notEmpty = takeLock.newCondition();
由于出入队可以同时进行,因此必须避免冲突问题。
- 同一元素操作冲突:由于 LinkedBlockingQueue 采用了 FIFO(先进先出)的原则,实际上是双端操作,不会存在冲突。并且在其内部定义了两个变量:head、last。
// 出队修改头节点private transient Node<E> head;// 入队修改尾节点private transient Node<E> last;
- 元素数量操作冲突:因为入队数量要+1,出队数量要-1,因此需要保证它的可见性,这里采用了这里采用原子类来实现:
private final AtomicInteger count = new AtomicInteger(0);
入队操作
- offer,该操作成功返回 true,失败返回 false。
public boolean offer(E e) { if (e == null){ // 抛出异常... } // 判断元素的个数是否超过容量4 final AtomicInteger count = this.count; if (count.get() == capacity){ return false; } int c = -1; Node<E> node = new Node(e); // 加锁 final ReentrantLock putLock = this.putLock; putLock.lock(); try { // 再次判断,存在等待获取锁期间,其他线程执行入队操作。 if (count.get() < capacity) { // 入队操作 enqueue(node); // 注意:数量+1,返回的旧值 c = count.getAndIncrement(); if (c + 1 < capacity){ // 队列未满,唤醒因为队列满而阻塞的线程 notFull.signal(); } } } finally { putLock.unlock(); } // 为 0 表示之前队列是空的,唤醒出队时因为空队列而进入 notEmpty 条件等待队列的线程 if (c == 0){ signalNotEmpty(); } return c >= 0;}
- put,该操作成功返回 true,失败则进入阻塞。
private final AtomicInteger count = new AtomicInteger(0);public void put(E e) throws InterruptedException { if (e == null){ // 抛出异常... } int c = -1; Node<E> node = new Node(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(); } if (c == 0){ signalNotEmpty(); }}
- 关键
private void enqueue(Node<E> node) { last = last.next = node;}private void signalNotEmpty() { final ReentrantLock takeLock = this.takeLock; takeLock.lock(); try { notEmpty.signal(); } finally { takeLock.unlock(); }}
- 入队操作的过程如下所示:
出队操作
- poll,成功返回被移除的元素,失败返回 null。
public E poll() { final AtomicInteger count = this.count; if (count.get() == 0){ return null; } E x = null; int c = -1; // 加锁 final ReentrantLock takeLock = this.takeLock; takeLock.lock(); try { if (count.get() > 0) { // 关键 -> 出队 x = dequeue(); c = count.getAndDecrement(); if (c > 1){ notEmpty.signal(); } } } finally { takeLock.unlock(); } // 表示出队前满队列,唤醒因入队时满队列而进入 notFull 条件等待队列的线程。 if (c == capacity){ signalNotFull(); } return x;}
- take,成功返回被移除的元素,失败则线程阻塞。
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;}
- 关键
private E dequeue() { // 头节点、以及它的后继节点 Node<E> h = head; Node<E> first = h.next; // 等于 h.next = null,即断开后指针 h.next = h; // 设置新的头节点 head = first; E x = first.item; // 将节点的值置空 first.item = null; return x;}private void signalNotFull() { final ReentrantLock putLock = this.putLock; putLock.lock(); try { notFull.signal(); } finally { putLock.unlock(); }}
- 出队过程如下图所示:
0 0
- 05.JUC 集合
- 01.JUC 集合
- 02.JUC 集合
- 04.JUC 集合
- 03.JUC 集合
- JUC集合--ConcurrentSkipListSet
- JUC集合---CopyOnWriteArrayList
- JUC集合---CopyOnWriteArraySet
- java多线程--JUC集合框架
- 学习笔记 07 --- JUC集合
- Java多线程系列--“JUC集合”
- JUC集合-02之 CopyOnWriteArrayList
- JUC集合-03之 CopyOnWriteArraySet
- JUC集合-04之 ConcurrentHashMap
- JUC集合-05之 ConcurrentSkipListMap
- JUC集合-06之 ConcurrentSkipListSet
- JUC集合-07之 ArrayBlockingQueue
- JUC集合-08之 LinkedBlockingQueue
- JQuery的筛选基础了解
- Opencv学习_3 (Opencv读取视频 &视频进度控制 &写视频)
- how to fix the frame size?
- hdu1686 Oulipo【kmp】
- jdbc连接数据库使用sid和service_name的区别
- 05.JUC 集合
- linux ethtool命令
- perl 多线程及信号控制
- JSP
- 加载中动画
- opencv学习_4(opencv基础数据结构 CvPoint & CvSize & CvRect & CvScalar & CvArr & CvMat)
- Comparable接口实现数组排序
- spoj 104 HIGH
- 正则表达式 验证YYYY-MM-DD HH:mm:ss,包含闰年验证(包含世纪年和普通闰年)