Java 为什么线程在持有锁时而不是在获取锁之前测试条件/属性?

Java 为什么线程在持有锁时而不是在获取锁之前测试条件/属性?,java,multithreading,synchronization,Java,Multithreading,Synchronization,来自Herlihy的多处理编程艺术: 假设有一根线 想要等到某个财产持有线程在 保持锁。如果属性不保持,则线程调用wait()来 释放锁并休眠,直到它被另一个线程唤醒 1 Condition condition = mutex.newCondition(); 2 ... 3 mutex.lock() 4 try { 5 while (!property) { // not happy 6 condition.await(); // wait for property 7

来自Herlihy的多处理编程艺术:

假设有一根线 想要等到某个财产持有线程在 保持锁。如果属性不保持,则线程调用wait()来 释放锁并休眠,直到它被另一个线程唤醒

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如何使用条件对象

为什么线程在测试属性之前而不是之后调用
mutex.lock()


谢谢。

如果您将此更改为:

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();

而属性为false。

获取锁所做的一件事是创建一个内存屏障,这样就不会使用可能已过时的缓存值检查条件

获取锁还可以确保检查的值不会被其他线程同时更改。否则,线程可以测试条件并继续获取锁,然后在获取锁时发现条件已更改。不管怎样,线程最终都需要在锁保持的情况下进行检查

线程希望确定锁定对象的状态,然后修改该状态,同时确保该状态不会由于另一个线程的干扰而从它下面改变。这意味着它必须在检查和操作之间保持锁定。线程在检查失败后等待(释放锁直到发出信号),然后在下一次检查之前获取锁。一旦检查成功,它就会保持锁,直到它可以完成对锁定对象的操作为止


仅当检查成功(如添加到有界缓冲区)时,对锁定对象执行的操作才有意义。或者,该操作可能涉及多个更改,其中所有更改都需要一起应用(如果锁定对象的数据结构不是为并发访问而设计的,如ArrayList,则该数据结构需要多个步骤来添加元素,并且干扰可能会损坏数据结构).

因为属性可以在检查和锁定之间更改。谢谢。为什么“您假设您只能在持有互斥锁的情况下更改属性,那么就您问题中的示例而言”?因为如果您可以在不持有互斥锁的情况下更改属性,那么您永远无法保证在检查它和调用wait之间不会在另一个线程上更改它。