来自Herlihy的多处理编程艺术:
假设一个线程 想要等到某个房产持有。 线程测试属性 持有锁。如果属性不成立,则线程调用await() 释放锁并睡觉,直到它被另一个线程唤醒。
1 Condition condition = mutex.newCondition(); 2 ... 3 mutex.lock() 4 try { 5 while (!property) { // not happy 6 condition.await(); // wait for property 7 } catch (InterruptedException e) { 8 ... // application-dependent response 9 } 10 ... // happy: property must hold 11 }
图8.2如何使用Condition对象。
为什么线程在测试属性之前调用mutex.lock()
(如果属性不持有,线程调用await()
)而不是之后?
感谢。
答案 0 :(得分:1)
如果您将其更改为:
while (!property) {
mutex.lock();
condition.await();
mutex.unlock();
最大的问题是如果属性值在行
之间发生变化while (!property) {
和行
mutex.lock();
然后,当它已经处于通过状态时,你会等待属性改变。
如果您认为只能在锁定互斥锁时更改属性,那么对于您问题中的示例,您无法调用
condition.await();
当财产处于通过状态时。
要详细说明这个假设,问题中的示例代码通常会以某种方式设置属性值。这可能与
有关void setProperty(boolean newproperty) {
mutex.lock();
property = newproperty;
condition.signalAll();
mutex.unlock();
}
如果没有第二部分,你永远不能保证只打电话
condition.await();
虽然属性是假的。
答案 1 :(得分:0)
获取锁定的一件事是创建一个内存屏障,以便不使用可能已过时的缓存值检查条件。
同时获取锁定可确保检查的值不会被其他某个线程同时更改。否则,线程可以测试条件并继续获取锁定,然后在获取锁定时找到更改的条件。该线程最终需要检查所持有的锁。
线程想要确定锁定对象的状态,然后修改该状态,同时保证由于另一个线程的干扰,该状态不会从其下面改变。这意味着它必须在检查和行动中保持锁定。线程在检查失败后等待(释放锁直到发出信号),然后在下次检查之前获取锁。一旦检查成功,它就会保持锁定,直到它可以完成对锁定对象的操作。
只有在检查成功时(如添加到有界缓冲区),对锁定对象执行的操作才有意义。或者操作可能涉及多个更改,其中所有更改都需要一起应用(如果锁定对象具有不是为并发访问而设计的数据结构,如ArrayList,那么数据结构需要多个步骤来添加元素,并且干扰可以破坏数据结构)。