/** The capacity bound, or Integer.MAX_VALUE if none */// 链表容量,指定容量就是有界队列privatefinalint capacity;/** Current number of elements */// 元素数量privatefinalAtomicInteger count =newAtomicInteger();/**
* Head of linked list.
* Invariant: head.item == null
*/// 链表头:本身是不存储任何元素的,初始化时item指向nulltransientNode<E> head;/**
* Tail of linked list.
* Invariant: last.next == null
*/// 链表尾privatetransientNode<E> last;/** Lock held by take, poll, etc */// take锁:锁分离,提高效率privatefinalReentrantLock takeLock =newReentrantLock();/** Wait queue for waiting takes */// notEmpty条件:当队列无元素时,take锁会阻塞在notEmpty条件上,等待其它线程唤醒privatefinalCondition notEmpty = takeLock.newCondition();/** Lock held by put, offer, etc */// put锁privatefinalReentrantLock putLock =newReentrantLock();/** Wait queue for waiting puts */// notFull条件:当队列满了时,put锁会会阻塞在notFull上,等待其它线程唤醒privatefinalCondition notFull = putLock.newCondition();// 单链表数据结构staticclassNode<E>{// 存储的元素E item;// //后继节点:单链表结构Node<E> next;// 构造方法,定义当前的节点Node(E x){ item = x;}}
LinkedBlockingQueue的构造方法源码分析
/**
* 默认无参的构造方法:直接调用队列大小是int最大长度的构造方法
*/publicLinkedBlockingQueue(){this(Integer.MAX_VALUE);}/**
* 指定容量的构造方法
* capacity:链表的最大长度
*/publicLinkedBlockingQueue(int capacity){// 传入最大的链表长度小于0,直接抛出异常if(capacity <=0)thrownewIllegalArgumentException();// 给链表的最大长度赋值this.capacity = capacity;// 初始化一个为null的头尾节点
last = head =newNode<E>(null);}/**
* 指定初始数据的构造方法
* c:可以将已经存在的列表初始化到阻塞队列中。
*/publicLinkedBlockingQueue(Collection<?extendsE> c){// 调用链表最大长度是int的最大值容量的构造方法this(Integer.MAX_VALUE);// 获取阻塞队列的内置锁finalReentrantLock putLock =this.putLock;// 获取锁操作
putLock.lock();// Never contended, but necessary for visibilitytry{// 零时变量,记录有几个元素int n =0;// 遍历集合中的每个元素for(E e : c){// 有空的元素,直接抛出异常if(e ==null)thrownewNullPointerException();// 长度与最大长度相同,抛异常!if(n == capacity)thrownewIllegalStateException("Queue full");// 添加到链表中enqueue(newNode<E>(e));// 总数量加一++n;}// 维护元素的格式
count.set(n);}finally{// 释放锁操作
putLock.unlock();}}/**
* 添加元素到队列中
*/privatevoidenqueue(Node<E> node){// 尾部插入:之前尾结点的下一个节点是当前节点,并且吧当前节点设置为最新的尾结点!
last = last.next = node;}
LinkedBlockingQueue的入队方法:put(E e) 源码分析
/**
* 往LinkedBlockingQueue中插入元素
*/publicvoidput(E e)throwsInterruptedException{// 如果元素是NULL,抛出异常if(e ==null)thrownewNullPointerException();// Note: convention in all put/take/etc is to preset local var// holding count negative to indicate failure unless set.// 定义一个用于接收数量的变量int c =-1;// 初始化当前的节点Node<E> node =newNode<E>(e);// 获取当前的put锁finalReentrantLock putLock =this.putLock;// 得到当前的元素个数finalAtomicInteger count =this.count;// 获取锁:优先考虑中断
putLock.lockInterruptibly();try{/*
* Note that count is used in wait guard even though it is
* not protected by lock. This works because count can
* only decrease at this point (all other puts are shut
* out by lock), and we (or some other waiting put) are
* signalled if it ever changes from capacity. Similarly
* for all other uses of count in other wait guards.
*/// 达到最大的容量,就阻塞在notFull上等待被其它线程唤醒(阻塞生产者线程)while(count.get()== capacity){
notFull.await();}// 队列没有满,入队操作!enqueue(node);// 原子类加一
c = count.getAndIncrement();// 如果队列还有空闲,准备唤醒被阻塞的生产者线程if(c +1< capacity)
notFull.signal();}finally{// 释放锁,真正唤醒生产者线程!
putLock.unlock();}// 原队列的长度为0,加了一个元素后立即唤醒阻塞在notEmpty上的线程if(c ==0)// 唤醒阻塞在notEmpty上的线程signalNotEmpty();}/**
* 唤醒阻塞在notEmpty上的线程
*/privatevoidsignalNotEmpty(){// 获取当前的take锁finalReentrantLock takeLock =this.takeLock;// 获取锁
takeLock.lock();try{// notEmpty条件转同步队列
notEmpty.signal();}finally{// 唤醒消费者线程
takeLock.unlock();}}