class BoundedBuffer {
final Lock lock = new ReentrantLock();
final Condition notFull = lock.newCondition();
final Condition notEmpty = lock.newCondition();
final Object[] items = new Object[100];
int putptr, takeptr, count;
public void put(Object x) throws InterruptedException {
lock.lock();
try {
while (count == items.length)
notFull.await();
items[putptr] = x;
if (++putptr == items.length) putptr = 0;
++count;
notEmpty.signal();
} finally {
lock.unlock();
}
}
public Object take() throws InterruptedException {
lock.lock();
try {
while (count == 0)
notEmpty.await();
Object x = items[takeptr];
if (++takeptr == items.length) takeptr = 0;
--count;
notFull.signal();
return x;
} finally {
lock.unlock();
}
}
}
Condition 问题 很不能理解为什么要用2个Condition
------最佳解决方案--------------------------------------------------------
当然可以使用一个Condition,但要注意,使用一个Condition的时候就要使用signalAll方法了,这换唤醒所有等待的线程,而最终可能只有一个线程的条件满足了,比如buffer现在是空的,有100个线程在等待,现在加入一个元素,唤醒了100个线程,线程从wait中醒来需要重新获取锁,这100个线程就要竞争同一把锁,而最终只有一个线程能消费这个元素,其它99个线程醒来后又继续while (count == 0)成立,继续await,在高并发下,这是非常大的竞争与上下文切换开销
为什么一个Condition就必须用notifyAll?因为这个Condition是作为两个条件断言使用的。
假设有buffer的长度是10,现在10个元素都被消费完了,且还有15个线程在上面等待
现在有10个线程各往里put一个元素,虽然每put一次都会做唤醒操作,但是存在唤醒的线程一直竞争不到锁的情况,于是那15个线程还在等待,而10个线程很幸运,在与那15个线程的竞争过程中都先获取到锁了,且把元素放进去了,这是bufer里就有10个元素了,也就是满了,put的线程又来了,这次又来了10个,他们都需要wait,现在是什么场景?有10个元素,15个线程在等待获取锁然后拿到元素,10个线程等待往buffer里塞东西,如果只有一个Condition,且使用的是signal而不是signalAll,在消费了一个元素后,本来该唤醒一个生产线程,而它却有可能唤醒的还是消费线程,因为消费线程和生产线程都在同一个条件队列里等待,这就出问题了。
如果LZ读过《Java concurrency in practice》第14章,将会看到很多BoundedBuffer的实现
http://www.ticmy.com/?p=219
------其他解决方案--------------------------------------------------------
所谓condition就是指条件嘛,一般是用来阻塞线程的,或者说满足某个条件才能让线程继续往下运行。
这里一个是表示满的状态,一个表示空的状态。
------其他解决方案--------------------------------------------------------
如果用一个不可以吗? 为什么不可以?