阻塞队列的操作,当不能立即满足时(但将来可能会满足),有4种形式处理方式:
1抛异常;2返回特殊值;3阻塞;4等待特定时间(时间内操作被满足返回true,超时返回false)
这里分析其阻塞的处理方式。
现在来看put方法的源码
public void put(E e) throws InterruptedException {
if (e == null) throw new NullPointerException();
// 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 = new Node<E>(e);//创建新节点,节点中包含一个数据字段item=e,和一个指针字段next
final ReentrantLock putLock = this.putLock;
final AtomicInteger 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.
*/
while (count.get() == capacity) {//LinkedBlockingQueue队满时进入循环
notFull.await();//主要包括操作三个:放入等待队列,释放锁,阻塞
}
enqueue(node);//入队
c = count.getAndIncrement();//返回原值
if (c + 1 < capacity)
notFull.signal();//如果当前队列未满,则signal非满条件,signal操作为:将等待队列中的firstwaiter出队,并进入同步队列,检查,如果同步队列中的前一个节点已经cancelled,则unpark刚进入的这个节点(否则不对这个节点进行处理)
} finally {
putLock.unlock();//解锁
}
if (c == 0)
signalNotEmpty();//如果队列中只有一个节点,则signal非空条件,操作如notFull.signal()
}
public final void await() throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
Node node = addConditionWaiter();//将当前线程加入等待队列,并设置状态为condition
int savedState = fullyRelease(node);//根据addConditionWaiter中新加节点可知,返回的state为condition。这里还会释放锁(即, 锁计数器减一,并unpark下一个节点(此处并不出队首节点,首节点在获取锁时出队),以便激活阻塞线程,并获得锁)
int interruptMode = 0;
while (!isOnSyncQueue(node)) {//不在同步队列(与等待队列区别)中时(此时线程已获得锁,必然在同步队列中,但此方法中还有一个判断条件是状态是否为condition,若是则返回false),进入循环
LockSupport.park(this);//阻塞在这里(并放弃锁,从而使得其他线程也可阻塞在这里,即等待队列中包含多个节点(线程)),不会向下进行,当signal发生时会继续执行;中断发生时,抛出
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
}
if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
interruptMode = REINTERRUPT;
if (node.nextWaiter != null) // clean up if cancelled
unlinkCancelledWaiters();
if (interruptMode != 0)
reportInterruptAfterWait(interruptMode);
}
private Node addConditionWaiter() {//将线程加入等待队列,并设置状态为condition
Node t = lastWaiter;
// If lastWaiter is cancelled, clean out.
if (t != null && t.waitStatus != Node.CONDITION) {
unlinkCancelledWaiters();
t = lastWaiter;
}
Node node = new Node(Thread.currentThread(), Node.CONDITION);
if (t == null)
firstWaiter = node;
else
t.nextWaiter = node;
lastWaiter = node;
return node;
}
final int fullyRelease(Node node) {//释放锁,并返回节点状态
boolean failed = true;
try {
int savedState = getState();
if (release(savedState)) {
failed = false;
return savedState;
} else {
throw new IllegalMonitorStateException();
}
} finally {
if (failed)
node.waitStatus = Node.CANCELLED;
}
}
public final boolean release(int arg) {
if (tryRelease(arg)) {//尝试释放锁
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);//unpark后继线程
return true;
}
return false;
}
protected final boolean tryRelease(int releases) {
int c = getState() - releases;
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
if (c == 0) {//如果没有线程持有锁
free = true;//释放锁成功
setExclusiveOwnerThread(null);//设置独占线程为null
}
setState(c);
return free;
}
private void unparkSuccessor(Node node) {//unpark后继线程
/*
* If status is negative (i.e., possibly needing signal) try
* to clear in anticipation of signalling. It is OK if this
* fails or if status is changed by waiting thread.
*/
int ws = node.waitStatus;
if (ws < 0)
compareAndSetWaitStatus(node, ws, 0);
/*
* Thread to unpark is held in successor, which is normally
* just the next node. But if cancelled or apparently null,
* traverse backwards from tail to find the actual
* non-cancelled successor.
*/
Node s = node.next;
if (s == null || s.waitStatus > 0) {
s = null;
for (Node t = tail; t != null && t != node; t = t.prev)
if (t.waitStatus <= 0)
s = t;
}
if (s != null)
LockSupport.unpark(s.thread);
}
Take方法细节可从put方法推出,就不分析了。
<pre name="code" class="java">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();//加入等待队列(与notFull.await()不是一个等待队列),释放锁,阻塞
}
x = dequeue();//出队
c = count.getAndDecrement();
if (c > 1)//队列非空
notEmpty.signal();//notFull等待队列出队一节点,节点入队同步队列
} finally {
takeLock.unlock();
}
if (c == capacity)
signalNotFull();
return x;
}