Condition介绍
1.Condition实现类ConditionObject是AQS中的内部类
2.Condition是依赖lock的,因为Condition中等待队列中的数据流向AQS等待队列的过程
3.每一个lock可以拥有多个condition
4.condition await signal/signalAll 和 synchronized+wait+notify/notifyAll功能比较类似,实现的逻辑也
比较类似;
当使用synchronized的wait方法,会将当前线程放入waitSet(睡眠的等待队列,不参与锁的竞争),
相当于使用condition调用await方法,将当前线程放入condition自己维护的队列中
当使用synchronized的方法notify方法会将waitSet中随机的一个线程移动到enterList(等待队列,参与锁的竞争)
相当于使用condition的signal方法,将队列中第一个元素移动到Lock的等待队列(AQS的等待队列,有机会参与锁的竞争)中去
代码示例
class BoundedContainer{
private String[] elements = new String[10];
private Lock lock = new ReentrantLock();
private Condition notEmptyCondition = lock.newCondition();
private Condition notFullCondition = lock.newCondition();
private int elementCount;
private int putIndex;
private int takeIndex;
public void put(String str) {
try {
lock.lock();
while(elementCount==elements.length) {
notFullCondition.await();
}
elements[putIndex] = str;
if(++ putIndex == this.elements.length) {
putIndex = 0;
}
++ elementCount;
System.out.println("put method: "+Arrays.toString(this.elements));
notEmptyCondition.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public String take() {
try {
lock.lock();
while(elementCount==0) {
notEmptyCondition.await();
}
String element = elements[takeIndex];
elements[takeIndex] = null;
if(++ takeIndex == this.elements.length) {
takeIndex = 0;
}
System.out.println("take method: "+Arrays.toString(this.elements));
notFullCondition.signal();
-- elementCount;
return element;
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
return null;
}
}
源码分析
ConditionObject包含的成员变量
private transient Node firstWaiter;
private transient Node lastWaiter;
获取方法newCondition
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
public Condition newCondition() {
return sync.newCondition();
}
final ConditionObject newCondition() {
return new ConditionObject();
}
Condition.await()
public final void await() throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
Node node = addConditionWaiter();
int savedState = fullyRelease(node);
int interruptMode = 0;
while (!isOnSyncQueue(node)) {
LockSupport.park(this);
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
}
if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
interruptMode = REINTERRUPT;
if (node.nextWaiter != null)
unlinkCancelledWaiters();
if (interruptMode != 0)
reportInterruptAfterWait(interruptMode);
}
Condition.signal
public final void signal() {
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
Node first = firstWaiter;
if (first != null)
doSignal(first);
}
private void doSignal(Node first) {
do {
if ( (firstWaiter = first.nextWaiter) == null)
lastWaiter = null;
first.nextWaiter = null;
} while (!transferForSignal(first) &&
(first = firstWaiter) != null);
}
final boolean transferForSignal(Node node) {
if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))
return false;
Node p = enq(node);
int ws = p.waitStatus;
if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
LockSupport.unpark(node.thread);
return true;
}