Java 为什么线程在持有锁时而不是在获取锁之前测试条件/属性?
来自Herlihy的多处理编程艺术: 假设有一根线 想要等到某个财产持有线程在 保持锁。如果属性不保持,则线程调用wait()来 释放锁并休眠,直到它被另一个线程唤醒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
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之间不会在另一个线程上更改它。