Ojbect:
wait\notify\notifyAll
Condition:
await\signal\signalAll
Condition接口API里使用两个condition是否有必要?
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(); } } }
有必要,应为这样写程序会更加清晰,比以前使用Object的wait/notify。 一个Condition代表一种条件,这个条件里面有一个链表,那么2个条件就有2条等待链表。 只要在等待的队列上被唤醒才能继续,如果同时被2个条件控制,那么就要分别被2个唤醒才行,这么写的好处是粒度细,控制更精细,不像Object的是粗粒度的。
请问用一个Condition是不是可以达到同样的效果呢? 当然可以,结构上没那么清晰了,没有JDK1.5的并发之前还不是用Object提供的wait写生产者消费者队列的 不过,同一个队列关联多个条件断言,用signal就危险了,要用sinalAll
内置锁对象只有一个条件队列,显式锁可以通过newCondition方法创建多个条件队列,这样就可以避免不同的条件断言关联同一个条件队列造成的问题。
有多个线程往里面存数据和从里面取数据,其队列(先进先出后进后出)能缓存的最大数值是capacity,多个线程间是互斥的,当缓存队列中存储的值达到capacity时,将写线程阻塞,并唤醒读线程,当缓存队列中存储的值为0时,将读线程阻塞,并唤醒写线程
这就是多个Condition的强大之处,假设缓存队列中已经存满,那么阻塞的肯定是写线程,唤醒的肯定是读线程,相反,阻塞的肯定是读线程,唤醒的肯定是写线程,那么假设只有一个Condition会有什么效果呢,缓存队列中已经存满,这个Lock不知道唤醒的是读线程还是写线程了,如果唤醒的是读线程,皆大欢喜,如果唤醒的是写线程,那么线程刚被唤醒,又被阻塞了,这时又去唤醒,这样就浪费了很多时间!
ArrayBlockingQueue中也使用了这种技术。