原文:http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/locks/Condition.html
这个例子很好的解释了ReentrantLock的条件锁-Condition的用法:
看完API文档中这个例子后,我很疑惑:如果线程A进入了take方法,并拿到了Lock的拥有权,同事阻塞在了await()方法处,此时线程B进入了put方法,线程B试图去获取Lock的拥有权,但之前线程A还没释放锁,岂不是线程B无法走到put方法的signal()处,这样就不造成线程死锁了吗!
这篇文章给了一个很好的解释:
Both Lock
and synchronized
temporarily allow others to obtain the lock when they are waiting. To stop waiting, a thread have to re-acquire the lock.
http://stackoverflow.com/questions/12578687/waiting-on-a-condition-in-a-reentrant-lock
原来Condtion.await()的时候线程A会允许其他线程来抢夺锁,当线程A的阻塞状态被唤醒后,线程A会重新去抢夺锁。
public interface Condition
Condition factors out the Object monitor methods (wait
, notify
and notifyAll
) into distinct objects to give the effect of having multiple wait-sets per object, by combining them with the use of arbitrary Lock
implementations. Where a Lock replaces the use of synchronized methods and statements, a Condition replaces the use of the Object monitor methods.
Conditions (also known as condition queues or condition variables) 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 atomicallyreleases the associated lock and suspends the current thread, just like Object.wait.
A Condition instance is intrinsically bound to a lock. To obtain a Condition instance for a particular Lock
instance use its newCondition()
method.
As an example, suppose we have a bounded buffer which supports put and take methods. If a take is attempted on an empty buffer, then the thread will block until an item becomes available; if a put is attempted on a full buffer, then the thread will block until a space becomes available. We would like to keep waiting put threads and 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 Condition
instances.
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(); } } }
(The ArrayBlockingQueue
class provides this functionality, so there is no reason to implement this sample usage class.)
A Condition implementation can provide behavior and semantics that is different from that of the Object monitor methods, such as guaranteed ordering for notifications, or not requiring a lock to be held when performing notifications. If an implementation provides such specialized semantics then the implementation must document those semantics.
Note that Condition instances are just normal objects and can themselves be used as the target in a synchronized statement, and can have their own monitor wait
and notification
methods invoked. Acquiring the monitor lock of a Condition instance, or using its monitor methods, has no specified relationship with acquiring the Lock
associated with that Condition or the use of its waiting
and signalling
methods. It is recommended that to avoid confusion you never use Condition instances in this way, except perhaps within their own implementation.
Except where noted, passing a null value for any parameter will result in a NullPointerException
being thrown.
Implementation Considerations
When waiting upon a Condition, a "spurious wakeup" is permitted to occur, in general, as a concession to the underlying platform semantics. This has little practical impact on most application programs as a Conditionshould always be waited upon in a loop, testing the state predicate that is being waited for. An implementation is free to remove the possibility of spurious wakeups but it is recommended that applications programmers always assume that they can occur and so always wait in a loop.
The three forms of condition waiting (interruptible, non-interruptible, and timed) may differ in their ease of implementation on some platforms and in their performance characteristics. In particular, it may be difficult to provide these features and maintain specific semantics such as ordering guarantees. Further, the ability to interrupt the actual suspension of the thread may not always be feasible to implement on all platforms.
Consequently, an implementation is not required to define exactly the same guarantees or semantics for all three forms of waiting, nor is it required to support interruption of the actual suspension of the thread.
An implementation is required to clearly document the semantics and guarantees provided by each of the waiting methods, and when an implementation does support interruption of thread suspension then it must obey the interruption semantics as defined in this interface.
As interruption generally implies cancellation, and checks for interruption are often infrequent, an implementation can favor responding to an interrupt over normal method return. This is true even if it can be shown that the interrupt occurred after another action may have unblocked the thread. An implementation should document this behavior.
相关推荐
- 当需要更精细的锁控制,如条件变量、可中断等待和公平性时,可以使用`ReentrantLock`。 - 对于高竞争的锁,非公平锁通常比公平锁有更好的性能,因为它减少了线程调度的开销。 - 谨慎使用`ReentrantLock`,避免过度...
ReentrantLock源码详解中最重要的一个部分就是条件锁,条件锁是指在获取锁之后发现当前业务场景自己无法处理,而需要等待某个条件的出现才可以继续处理时使用的一种锁。今天我们来详细介绍条件锁的原理和实现。 ...
`ReentrantLock`的`lockInterruptibly()`方法允许线程在等待锁时被中断,这在处理长时间等待的情况时非常有用。与`synchronized`不同,`synchronized`锁无法响应中断请求,除非释放锁。 4. **锁的状态检查**: - ...
此外,ReentrantLock还支持锁的条件条件(Condition),使得线程可以在满足特定条件时才被唤醒,增加了灵活性。在高并发竞争环境下,ReentrantLock的性能通常优于Synchronized,因为它减少了不必要的锁同步开销。 ...
ReentrantLock可以提供更好的灵活性和可控性,例如,可以使用Condition来实现线程之间的通信。 ReentrantLock的使用场景非常广泛,例如,可以用于解决多线程访问共享资源的问题、实现线程之间的同步访问资源、避免...
* 使用ReentrantLock时,JVM不能自动释放锁,需要手动释放锁。 * 使用ReentrantLock时,JVM不能包括锁定信息在线程转储中,对调试不太友好。 Condition是ReentrantLock的一个伴随类,提供了对线程的等待和唤醒等...
- 分离锁和条件:`ReentrantLock`有`Condition`接口,可以创建多个条件,每个条件对应一个等待队列,提高了线程间的协作能力。 4. **灵活性**: - 更好的控制粒度,可以只锁定需要的部分代码,提高并发效率。 - ...
7. **可中断的等待**:与synchronized不同,使用ReentrantLock的线程可以在等待锁时被中断,通过调用Condition的await()方法进入等待状态,当其他线程调用signal()方法或线程被中断时,等待的线程会被唤醒。...
然而,与内置锁不同的是,使用ReentrantLock需要显式调用`lock()`和`unlock()`方法来获取和释放锁,这增加了更多的控制和高级功能。 ReentrantLock实现了Lock接口,提供了以下几个关键方法: 1. `lock()`: 阻塞直到...
Condition的等待和唤醒操作比Object的wait/notify更安全,因为它们只能在已获取锁的上下文中执行,减少了死锁和竞态条件的风险。 ReentrantLock的这些特性使得它在某些复杂的并发场景下更为适用,例如,当需要精确...
本篇文章将深入探讨`ReentrantLock`的使用,它是Java并发包`java.util.concurrent.locks`中的一个高级锁机制,相比传统的`synchronized`关键字,提供了更丰富的功能和更灵活的控制。 `ReentrantLock`全称为可重入锁...
此外,ReentrantLock还支持更高级的功能,如条件变量(Condition),这允许开发者创建独立于锁本身的等待队列,实现更复杂的同步逻辑。例如,可以使用`newCondition()`创建一个条件,然后通过`await()`和`signal()`...
总结起来,`java多线程的条件对象和锁对象demo`这个例子展示了如何利用`ReentrantLock`和`Condition`来精细控制多线程的执行。它教导我们如何通过条件等待和信号机制实现线程间的协同工作,以及如何利用锁对象来保证...
6. **锁的条件条件**:`Condition`接口提供了与`synchronized`中`wait()`和`notify()`类似的功能,但更灵活,可以创建多个条件,每个条件对应一组等待线程。 在实际开发中,选择`synchronized`还是`ReentrantLock`...
本文将深入探讨JavaLock中的ReentrantLock(可重入锁)以及与其紧密相关的Condition接口,帮助你理解它们的工作原理和应用场景。 **一、ReentrantLock可重入锁** ReentrantLock是Java.util.concurrent.locks包下的...
ReentrantLock的基本用法 2.1 创建ReentrantLock 2.2 获取锁和释放锁 公平性与非公平性 3.1 公平锁 3.2 非公平锁 中断响应 条件变量与Condition 5.1 创建Condition 5.2 await()和signal() 可重入性 ReentrantLock与...
3. 条件队列:ReentrantLock提供了Condition机制,允许多个线程等待不同的条件满足,并且可以根据条件谓词来唤醒对应的线程。 内置锁和显式锁都是Java中用于同步的机制,但是它们有着不同的优点和缺点。内置锁简单...
- CONDITION (-2): 节点处于某个条件队列中,等待被唤醒。 - PROPAGATE (-3): 用于可传播的节点,确保在某些操作中不会阻塞其他操作。 总结来说,ReentrantLock在Java多线程编程中扮演着关键角色,提供了灵活的锁...
但是,`Condition`的这些方法需要在持有相应`Lock`的情况下调用,且可以针对特定的条件进行操作。 ### Condition的主要方法 - `await()`: 当前线程在接收到信号或者被中断之前会一直等待。调用此方法后,线程会...