上一篇我们对ReentrantLock的API进行了详细的分析,相比于synchronized单个条件等待通知,ReentrantLock的多条件支持是核心优势之一,能进行更精细的多线程并发协同控制,而这核心优势依赖于与Condition接口的配合使用。本来就来进一步学习Condition接口的相关API。
认识Condition接口
要用ReentrantLock实现多条件并发协同,必须配合Condition接口使用,Condition接口是用于线程间协调通信的核心工具,下面我们就来分析下Condition接口的的相关API。
代替传统wait()/notify()
/**
* {@code Condition} factors out the {@code Object} monitor
* methods ({@link Object#wait() wait}, {@link Object#notify notify}
* and {@link Object#notifyAll notifyAll}) into distinct objects to
* give the effect of having multiple wait-sets per object, by
* combining them with the use of arbitrary {@link Lock} implementations.
* Where a {@code Lock} replaces the use of {@code synchronized} methods
* and statements, a {@code Condition} replaces the use of the Object
* monitor methods.
*/
Condition 将Object的监视器方法,Object#wait() 、Object#notify 和 Object#notifyAll分解为独立对象,通过与任意Lock接口的实现结合, 实现每个对象拥有多个等待集的效果。当Lock接口替代了synchronized方法和语句时,Condition 则替代了 Object 的监视器方法。
条件变量
/* <p>Conditions (also known as <em>condition queues</em> or
* <em>condition variables</em>) provide a means for one thread to
* suspend execution (to "wait") until notified by another
* thread that some state condition may now be true. Because access
* to this shared state information occurs in different threads, it
* must be protected, so a lock of some form is associated with the
* condition. The key property that waiting for a condition provides
* is that it <em>atomically</em> releases the associated lock and
* suspends the current thread, just like {@code Object.wait}.
*/
Conditions(也称为条件队列或 条件变量)提供了一种机制,使一个线程可暂停执行(进入“等待”状态),直到另一线程通知其某些状态条件可能已为真。由于共享状态信息在不同线程中被访问,必须通过某种形式的锁进行保护,因此条件总与锁关联。等待条件的关键特性是:它能原子性地释放关联锁并挂起当前线程,类似Object.wait的行为。
/* <p>A {@code Condition} instance is intrinsically bound to a lock.
* To obtain a {@code Condition} instance for a particular {@link Lock}
* instance use its {@link Lock#newCondition newCondition()} method.
*/
Condition实例本质上绑定到一个锁。为特定 Lock实例获取Condition实例,需使用其 Lock接口的newCondition() 方法。
/* <p>As an example, suppose we have a bounded buffer which supports
* {@code put} and {@code take} methods. If a
* {@code take} is attempted on an empty buffer, then the thread will block
* until an item becomes available; if a {@code put} is attempted on a
* full buffer, then the thread will block until a space becomes available.
* We would like to keep waiting {@code put} threads and {@code take}
* threads in separate wait-sets so that we can use the optimization of
* only notifying a single thread at a time when items or spaces become
* available in the buffer. This can be achieved using two
* {@link Condition} instances.
*/
经典用法
例如,假设有一个支持put和take方法的有界缓冲区。若在空缓冲区上尝试take,线程将阻塞直至有可用项;若在满缓冲区上尝试put,线程将阻塞直至有可用空间。通过分离put线程和take线程至不同等待集,可在缓冲区有项或空间时仅通知单一线程以优化性能。这可通过两个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, t

最低0.47元/天 解锁文章

被折叠的 条评论
为什么被折叠?



