1、wait,notify,notifyAll
同一个对象Object o,线程A调用wait方法在o的阻塞队列上进行等待a条件满足的notify通知,线程B调用wait方法在o的阻塞队列上进行等待b条件满足的notify通知。
对象o上的阻塞队列中等待的任务不是同一种类型,导致为了避免通知信号丢失,而使用notifyAll进行通知,也就是说A或者B中的某一个满足条件时,要使用notifyAll来通知等待在o上的所有阻塞线程。
因为假设当线程A线程满足等待条件时,使用notify进行通知时,通知的阻塞线程可能是A,也可能是B,如果通知到B的话,那就发生了信号丢失,实际想要通知的线程并没有获得通知。只有使用notifyAll才能保证通知到o上所有的阻塞线程。
2、Lock,Condition
一个Condition和一个Lock关联在一起,就像一个对象上的一个等待通知线程与阻塞队列一样。每个Lock,可以创建任意数量的Condition对象。调用lock上的Lock.newCondition方法即可。
特别注意:在Condition对象中,与wait、notify和notifyAll方法对应的分别是await、signal和signalAll。但是,Condition对Object进行了扩展,因而它也包含wait和notify方法。一定要确保使用正确的版本—await和signal。
3、使用显示条件变量的有界缓存
@ThreadSafe
public class ConditionBoundedBuffer <T> {
protected final Lock lock = new ReentrantLock();
// CONDITION PREDICATE: notFull (count < items.length)
private final Condition notFull = lock.newCondition();
// CONDITION PREDICATE: notEmpty (count > 0)
private final Condition notEmpty = lock.newCondition();
private static final int BUFFER_SIZE = 100;
@GuardedBy("lock") private final T[] items = (T[]) new Object[BUFFER_SIZE];
@GuardedBy("lock") private int tail, head, count;
// BLOCKS-UNTIL: notFull
public void put(T x) throws InterruptedException {
lock.lock();
try {
while (count == items.length)
notFull.await();
items[tail] = x;
if (++tail == items.length)
tail = 0;
++count;
notEmpty.signal();
} finally {
lock.unlock();
}
}
// BLOCKS-UNTIL: notEmpty
public T take() throws InterruptedException {
lock.lock();
try {
while (count == 0)
notEmpty.await();
T x = items[head];
items[head] = null;
if (++head == items.length)
head = 0;
--count;
notFull.signal();
return x;
} finally {
lock.unlock();
}
}
}