按关键词阅读:
为了实现弱一致性的迭代器 , 看来我们需要使所有节点都可以从先前的出队节点GC到达 。
这将导致两个问题:
- 允许恶意的Iterator导致无限的内存保留
- 如果某个节点在使用期间处于使用期 , 则导致旧节点到新节点的跨代链接 , 这导致了一代代GC难以处理 , 从而导致重复的主要集合 。
我们使用链接刚刚退出队列的Node的技巧 。
这样的自链接意味着前进到head.next 。
类定义实现了 BlockingQueue 接口 , 继承自 AbstractQueue 抽象类 。
public class LinkedBlockingQueue extends AbstractQueueimplements BlockingQueue, java.io.Serializable {private static final long serialVersionUID = -6903933977591709194L;}
序列化有趣的是此类支持序列化 , 但是Node并不支持序列化 , 因此fist/last就不能序列化 , 那么如何完成序列化/反序列化过程呢?private void writeObject(java.io.ObjectOutputStream s)throws java.io.IOException {lock.lock();try {// Write out capacity and any hidden stuffs.defaultWriteObject();// Write out all elements in the proper order.for (Node p = first; p != null; p = p.next)s.writeObject(p.item);// Use trailing null as sentinels.writeObject(null);} finally {lock.unlock();}}private void readObject(java.io.ObjectInputStream s)throws java.io.IOException, ClassNotFoundException {s.defaultReadObject();count = 0;first = null;last = null;// Read in all elements and place in queuefor (;;) {E item = (E)s.readObject();if (item == null)break;add(item);}}
描述的是LinkedBlockingDeque序列化/反序列化的过程 。序列化时将真正的元素写入输出流 , 最后还写入了一个null 。
读取的时候将所有对象列表读出来 , 如果读取到一个null就表示结束 。
这就是为什么写入的时候写入一个null的原因 , 因为没有将count写入流 , 所以就靠null来表示结束 , 省一个整数空间 。
内部变量基本节点
/** * Linked list node class * 单向的链表节点 。*/static class Node {E item;/*** One of:* - the real successor Node* - this Node, meaning the successor is head.next* - null, meaning there is no successor (this is the last node)*/Node next;Node(E x) { item = x; }}/** The capacity bound, or Integer.MAX_VALUE if none ** 队列的容量大小*/private final int capacity;/** Current number of elements ** aotmic 变量 , 用于统计元素个数*/private final AtomicInteger count = new AtomicInteger();/** * Head of linked list. * Invariant: head.item == null * 头节点 */transient Node head;/** * Tail of linked list. * Invariant: last.next == null * 尾巴节点 */private transient Node last;
并发控制/** Lock held by take, poll, etc */private final ReentrantLock takeLock = new ReentrantLock();/** Wait queue for waiting takes */private final Condition notEmpty = takeLock.newCondition();/** Lock held by put, offer, etc */private final ReentrantLock putLock = new ReentrantLock();/** Wait queue for waiting puts */private final Condition notFull = putLock.newCondition();
构造器实际上这个默认容量这么大 , 感觉是用不到的 。不过既然是 LinkedList 基于链表实现 , 大概是想表达长度不受限制的意思 。
/** * Creates a {@code LinkedBlockingQueue} with a capacity of * {@link Integer#MAX_VALUE}. */public LinkedBlockingQueue() {this(Integer.MAX_VALUE);}/** * Creates a {@code LinkedBlockingQueue} with the given (fixed) capacity. * * @param capacity the capacity of this queue * @throws IllegalArgumentException if {@code capacity} is not greater *than zero */public LinkedBlockingQueue(int capacity) {if (capacity <= 0) throw new IllegalArgumentException();this.capacity = capacity;// 初始化头结点和尾巴节点last = head = new Node(null);}
还有一个基于集合初始化的构造器:/** * Creates a {@code LinkedBlockingQueue} with a capacity of * {@link Integer#MAX_VALUE}, initially containing the elements of the * given collection, * added in traversal order of the collection's iterator. * * @param c the collection of elements to initially contain * @throws NullPointerException if the specified collection or any *of its elements are null */public LinkedBlockingQueue(Collection extends E> c) {// 首先初始化基本属性this(Integer.MAX_VALUE);// 声明一个写入锁final ReentrantLock putLock = this.putLock;putLock.lock(); // Never contended, but necessary for visibilitytry {int n = 0;for (E e : c) {// 禁止元素为 nullif (e == null)throw new NullPointerException();if (n == capacity)throw new IllegalStateException("Queue full");enqueue(new Node(e));++n;}count.set(n);} finally {putLock.unlock();}}
这里问一下大家 , 为什么禁止为 null 呢?BlockingQueue 不接受 null 值的插入 , 相应的方法在碰到 null 的插入时会抛出 NullPointerException 异常 。
稿源:(未知)
【傻大方】网址:http://www.shadafang.com/c/111J2HT2020.html
标题:阻塞队列(3)LinkedBlockingQueue源码详解( 二 )