Conditionは消費者生産者モデルを実現する


Condition条件変数は大きくObjectを解決するためである.wait/notify/notifyAllが使いにくい問題.
条件(条件キューまたは条件変数とも呼ばれる)は、ある状態条件がtrueの別のスレッドに通知される前にスレッドを保留する(すなわち、スレッドを「待機」させる)ための意味をスレッドに提供します.).この共有ステータス情報にアクセスするには、異なるスレッドで発生するため、保護される必要があります.そのため、条件に何らかのロックを関連付ける必要があります.条件の提供を待つ主な属性は、関連するロックを原子的に解放し、Objectのように現在のスレッドを掛けることである.waitがやったように.上記APIの説明は、条件変数がロックにバインドされる必要があり、複数のConditionが同じロックにバインドされる必要があることを示している.
前述のロックでは、条件変数を取得する方法はロックである.newCondition().
void await() throws InterruptedException; 
void awaitUninterruptibly();
long awaitNanos(long nanosTimeout) throws InterruptedException;
boolean await(long time, TimeUnit unit) throws InterruptedException;
boolean awaitUntil(Date deadline) throws InterruptedException;
void signal();
void signalAll();

以上はConditionインタフェースの定義方法である、await*はObjectに対応する.wait,signalはObjectに対応する.notify,
SignalAllはObjectに対応する.notifyAll.特にConditionのインタフェースの名前を変更するのは避けるためです
Conditionにもwait/notify/notifyAllメソッドがあるため、Objectのwait/notify/notifyAllの意味と使用とは混同されます.各ロックには任意のデータのConditionオブジェクトがあり、Conditionはロックにバインドされています.
だからロックの公平性の特性があります:もし公平なロックならば、スレッドはFIFOの順序に従ってConditionからです.awaitでリリースし、
非公平ロックであれば、後続のロック競争はFIFO順序を保証しない.Conditionを使用して生産者消費者を実現するモデルの例は以下の通りである.
package juc;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
* Condition ,
*
* @author donald 2017 3 2 7:02:17
* @param
*/
public class ProductQueue {
private final T[] items;
private final Lock lock = new ReentrantLock();
private Condition notFull = lock.newCondition();//
private Condition notEmpty = lock.newCondition();//
// , ,
private int head, tail, count;
/**
*
* @param maxSize
*/
@SuppressWarnings("unchecked")
public ProductQueue(int maxSize) {
items = (T[]) new Object[maxSize];
}

public ProductQueue() {
this(10);
}
/**
*
* @param t
* @throws InterruptedException
*/
public void put(T t) throws InterruptedException {
lock.lock();
try {
while (count == getCapacity()) {
// ReentrantLock is oweself, await for realse the lock and put up
// the thread
// when the condition is satsfy ,the get the lock and run
// ,
notFull.await();
}
//
items[tail] = t;
if (++tail == getCapacity()) {
// , , ,
tail = 0;
}
//
++count;
// , lock,
notEmpty.signalAll();
} finally {
lock.unlock();
}
}
/**
*
* @return
* @throws InterruptedException
*/
public T take() throws InterruptedException {
lock.lock();
try {
while (count == 0) {
// ,
notEmpty.await();
}
T ret = items[head];
// ,
items[head] = null;// help GC
// , head
if (++head == getCapacity()) {
head = 0;
}
//
--count;
// , lock,
notFull.signalAll();
return ret;
} finally {
lock.unlock();
}
}
/**
*
* @return
*/
public int getCapacity() {
return items.length;
}
/**
*
* @return
*/
public int size() {
lock.lock();
try {
return count;
} finally {
lock.unlock();
}
}

}

この例では、take()を消費するには、notEmptyの信号が受信されるまで、キューが空でない必要がある.生産put()はキューが必要で不満で、満タンになったらnotFullの信号が届くまで保留します.