JDK1.8源码泛读之ArrayBlockingQueue
线程池阻塞队列之:ArrayBlockingQueue
其内部以数组和ReentrantLock锁的方式实现的阻塞队列。
初始化队列长度,并且设置了基于同一个reentrantlock的条件Condition。
- items内部数组,长度必须初始化
- lock内部Reentrantlock对象
- notEmpty:队列不是空的Condition
- notFull:队列没有满Condition
添加队列元素
1 public void put(E e) throws InterruptedException { 2 checkNotNull(e); 3 final ReentrantLock lock = this.lock; 4 //同步锁开启 5 lock.lockInterruptibly(); 6 try { 7 //如果队列已经满了,进行已满条件阻塞,直到有人取出元素,导致notFull.signal 8 while (count == items.length) 9 notFull.await(); 10 //添加到队列 11 enqueue(e); 12 } finally { 13 lock.unlock(); 14 } 15 } 16 17 private void enqueue(E x) { 18 final Object[] items = this.items; 19 items[putIndex] = x; 20 if (++putIndex == items.length) 21 putIndex = 0; 22 count++; 23 //这个时候队列非空了 24 notEmpty.signal(); 25 }
队列取元素:
1 public E take() throws InterruptedException { 2 final ReentrantLock lock = this.lock; 3 //同步锁开启 4 lock.lockInterruptibly(); 5 try { 6 //队列为空,进行以空条件阻塞,直到有元素导致notEmpty.signal 7 while (count == 0) 8 notEmpty.await(); 9 //取元素 10 return dequeue(); 11 } finally { 12 lock.unlock(); 13 } 14 } 15 16 private E dequeue() { 17 final Object[] items = this.items; 18 @SuppressWarnings("unchecked") 19 E x = (E) items[takeIndex]; 20 items[takeIndex] = null; 21 if (++takeIndex == items.length) 22 takeIndex = 0; 23 count--; 24 if (itrs != null) 25 itrs.elementDequeued(); 26 //这个时候队列不满了 27 notFull.signal(); 28 return x; 29 }
那么`ReentrantLock`的`Condition`又是如何来实现当前线程的等待的呢。
通过`ReentrantLock`源码可以发现,其内部定义了一个方法:
1 public Condition newCondition() { 2 return sync.newCondition(); 3 }
sync是其内部类,并且继承了抽象类 `AbstractQueuedSynchronizer`,sync整个构建NewCondition的过程,其实是初始化了
AbstractQueuedSynchronizer的一个内部类:`ConditionObject`
AQS参考:【http://blog.csdn.net/aesop_wubo/article/details/7555956】
那么ConditionObject又做了什么,来实现等待和唤醒的过程的呢。
问题就转到类ConditionObject的两个方法的分析上:await/signal。
await方法,构建一个等待链表,以当前线程为“键”,并且中断当前线程:
1 public final void await() throws InterruptedException { 2 if (Thread.interrupted()) 3 throw new InterruptedException(); 4 5 //构建Waiter等待现场链表,Node内以当前线程对象为键 6 Node node = addConditionWaiter(); 7 8 //以下代码对node节点的线程进行相关状态的判断,最终是执行了线程的 9 // LockSupport.park(this);方法,也就是阻塞线程 10 11 int savedState = fullyRelease(node); 12 int interruptMode = 0; 13 while (!isOnSyncQueue(node)) { 14 LockSupport.park(this); 15 if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) 16 break; 17 } 18 if (acquireQueued(node, savedState) && interruptMode != THROW_IE) 19 interruptMode = REINTERRUPT; 20 if (node.nextWaiter != null) // clean up if cancelled 21 unlinkCancelledWaiters(); 22 if (interruptMode != 0) 23 reportInterruptAfterWait(interruptMode); 24 25 } 26 27 private Node addConditionWaiter() { 28 Node t = lastWaiter; 29 // If lastWaiter is cancelled, clean out. 30 if (t != null && t.waitStatus != Node.CONDITION) { 31 unlinkCancelledWaiters(); 32 t = lastWaiter; 33 } 34 Node node = new Node(Thread.currentThread(), Node.CONDITION); 35 if (t == null) 36 firstWaiter = node; 37 else 38 t.nextWaiter = node; 39 lastWaiter = node; 40 return node; 41 }
signal:内部遍历了等待链表,以CAS的方式修改节点状态,并且唤醒等待线程。
1 public final void signal() { 2 if (!isHeldExclusively()) 3 throw new IllegalMonitorStateException(); 4 Node first = firstWaiter; 5 if (first != null) 6 doSignal(first); 7 } 8 9 private void doSignal(Node first) { 10 do { 11 if ( (firstWaiter = first.nextWaiter) == null) 12 lastWaiter = null; 13 first.nextWaiter = null; 14 } while (!transferForSignal(first) && 15 (first = firstWaiter) != null); 16 } 17 18 final boolean transferForSignal(Node node) { 19 20 if (!compareAndSetWaitStatus(node, Node.CONDITION, 0)) 21 return false; 22 23 Node p = enq(node); 24 int ws = p.waitStatus; 25 //唤醒了等待线程 26 if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL)) 27 LockSupport.unpark(node.thread); 28 return true; 29 }
自此,阻塞队列ArrayBlockingQueue其实底层还是用到了ReentrantLock类和AbstractQueuedSynchronizer的锁机制来实现,无非是高层的引用类罢了。