简体   繁体   English

廉价的读写锁中的冗余挥发?

[英]redundant volatile in cheap read-write lock?

Brian Goetz in his article from https://www.ibm.com/developerworks/java/library/j-jtp06197/ Brian Goetz在他的文章中来自https://www.ibm.com/developerworks/java/library/j-jtp06197/

uses the example pasted below as a cheap read-write lock. 使用下面粘贴的示例作为便宜的读写锁。 My question is that if the int variable value is not declared volatile then would it make a difference? 我的问题是,如果不将int变量值声明为volatile,那会有所作为吗? My understanding is that since the writes to value are done within a synchronized block so latest value will be visible to other threads any way and therefore declaring it volatile is redundant. 我的理解是,由于对值的写入是在同步块内完成的,因此最新值将以任何方式对其他线程可见,因此将其声明为volatile是多余的。 Please clarify? 请澄清?

@ThreadSafe
public class CheesyCounter {
// Employs the cheap read-write lock trick
// All mutative operations MUST be done with the 'this' lock held
@GuardedBy("this") private volatile int value;

public int getValue() { return value; }

public synchronized int increment() {
    return value++;
}

} }

public synchronized int increment()

This synchronized prevents you from skipping an increment if two threads or more were trying to increment at the same time (because ++ is not atomic). 如果两个或两个以上线程试图同时递增(因为++不是原子的),则此synchronized可防止您跳过递增。

private volatile int value

This prevents you from seeing an outdated value in one thread which was already incremented in another thread. 这样可以防止您在一个线程中看到过时的值,而该值在另一个线程中已递增。 (Note that we could also have made getValue synchronized to achieve this) (请注意,我们也可以使getValue同步以实现此目的)

My understanding is that since the writes to value are done within a synchronized block so latest value will be visible to other threads any way 我的理解是,由于对值的写入是在同步块内完成的,因此最新值将以任何方式对其他线程可见

This is incorrect. 这是不正确的。 Generally, there is no guarantee that other threads "see" changes to variables as soon as the change is made. 通常,不能保证其他线程在进行更改后就立即“看到”对变量的更改。 A thread may see a stale value for a changed variable because, eg the thread sees the value really in a register instead of main memory. 线程可能会看到已更改变量的过时值,因为例如,线程实际上在寄存器中而不是在主存储器中看到了该值。

A volatile variable establishes "happens-before" semantics. volatile变量建立“先于发生”的语义。 The JLS, section 17.4.5 , states: JLS第17.4.5节指出:

Two actions can be ordered by a happens-before relationship. 可以通过事前发生关系来排序两个动作。 If one action happens-before another, then the first is visible to and ordered before the second. 如果一个动作发生在另一个动作之前 ,则第一个动作对第二个动作可见,并在第二个动作之前排序。

  • A write to a volatile field (§8.3.1.4) happens-before every subsequent read of that field. 随后每次对该字段进行读取之前,都会写入一个volatile字段(第8.3.1.4节)。

The JLS, Section 8.3.1.4 : JLS,第8.3.1.4节

A field may be declared volatile , in which case the Java Memory Model ensures that all threads see a consistent value for the variable (§17.4). 可以将字段声明为volatile ,在这种情况下,Java内存模型可确保所有线程看到的变量值均一致(第17.4节)。

The reason that the field must be volatile is that even though the read is atomic, it needs to ensure that the value is current -- that any value previously written by another thread is visible. 该字段必须是volatile的原因是,即使读取是原子的,它也需要确保该值是最新的-先前由另一个线程写入的任何值都是可见的。 The read being atomic is not enough; 读是原子的还不够; volatile is still necessary to ensure consistency of the value. 为了确保值的一致性,仍然必须使用volatile

Thanks very much for the answers guys. 非常感谢你们的答案。 Found this on oracle website as well now: "Second, when a synchronized method exits, it automatically establishes a happens-before relationship with any subsequent invocation of a synchronized method for the same object." 现在在oracle网站上也发现了这一点:“其次,当同步方法退出时,它会自动与任何后续调用同一对象的同步方法建立先发生后关系。” https://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html https://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 带hashmap的廉价读写锁 - Cheap read-write lock with hashmap 同步对易失性字段的写入访问(廉价读写块) - Synchronize write access to Volatile field (Cheap read-write block) 将volatile和synchronized混合为读写锁 - Mix volatile and synchronized as a read-write lock Java中读写操作的易变变量 - Volatile variable for read-write operations in Java 在读写原子性、可见性和防止重新排序方面,锁定、同步、原子变量与 Java 中的 volatile - Lock vs synchronized vs atomic variables vs volatile in java in terms of read-write atomicity, visibility and protection from reordering 为什么TreeBin在ConcurrentHashMap中保持读写锁定? - why TreeBin maintains a read-write lock in ConcurrentHashMap? 如何使用 JUnit 测试读写锁? - How to test read-write lock using JUnit? 有关读写锁的查询 - Query regarding read-write locks 易失性读取是否发生在易失性写入之前? - Is volatile read happens-before volatile write? 为什么 Spring 中的 ConcurrentLruCache 即使使用了读写锁,仍然使用线程安全的映射和队列,而不是普通的映射和队列? - Why does ConcurrentLruCache in Spring still use thread-safe maps and queues instead of ordinary maps and queues even when read-write lock are used?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM