Writing to a volatile field has the same memory effect as a monitor release,and reading from a volatile field has the same memory effect as a monitor acquire.
和
Effectively,the semantics of volatile have been strengthened substantially,almost to the level of synchronization. Each read or write of a volatile field acts like “half” a synchronization,for purposes of visibility.
从here.
这是否意味着,对volatile变量的任何写入都会使执行线程将其缓存刷新到主内存中,并且每次从volatile字段读取都会使线程从主内存重新读取其变量?
我问,因为同一文本包含此声明
Important Note: Note that it is important for both threads to access the same volatile variable in order to properly set up the happens-before relationship. It is not the case that everything visible to thread A when it writes volatile field f becomes visible to thread B after it reads volatile field g. The release and acquire have to “match” (i.e.,be performed on the same volatile field) to have the right semantics.
这句话让我很困惑.我知道对于使用synchronized语句定期获取和释放不是这样 – 如果某个线程释放任何监视器,那么它所做的所有更改都会明显地变为所有其他线程(更新:实际上不是真的 – 请注意最佳答案). stackoverflow上甚至有一个question about it.然而据说无论出于何种原因,情况并非如此.我无法想象发生在事先保证的任何实现,它不会使其他线程看到更改,这些线程不会读取相同的volatile变量.至少想象一个实现,它与前两个引号并不矛盾.
此外,在发布这个问题之前,我做了一些研究,例如this article,其中包含这个句子
After executing these instructions,all writes are visible to all other threads through cache subsystem or main memory.
提到的指令是在写入易失性字段时发生的指令.
那么这个重要的音符应该是什么意思?或者我错过了什么?或许这个说明完全错了?
回答?
在进行了一些更多的研究之后,我只能在官方文档中找到关于volatile字段及其对非易失性字段更改的影响的声明:
Using volatile variables reduces the risk of memory consistency errors,because any write to a volatile variable establishes a happens-before relationship with subsequent reads of that same variable. This means that changes to a volatile variable are always visible to other threads. What’s more,it also means that when a thread reads a volatile variable,it sees not just the latest change to the volatile,but also the side effects of the code that led up the change.
从here.
我不知道这是否足以得出结论,这种情况发生在关系只保证读取相同的volatile的线程之前.所以现在我只能总结一下结果是不确定的.
但实际上,我建议考虑线程A在写入易失性字段时所做的更改,只有当线程B读取相同的volatile字段时才能保证线程B可见.官方消息来源的上述引用强烈暗示.
解决方法
而你错误的根本所在:
I know for sure that it’s not true for regular lock acquire…
实际上,在x86上,你可能是对的,但是JLS and the official oracle tutorial mandates that:
When a thread releases an intrinsic lock,a happens-before relationship is established between that action and any subsequent acquisition of the same lock.
Happens-before为后续操作建立(如果需要,请阅读两个操作,如果它更简单).一个线程释放锁定,另一个线程获取它 – 这些是后续的(释放 – 获取语义).
对于volatile来说也会发生同样的事情 – 一些线程会写入,当某个其他线程通过后续读取观察到写入时,就会发生before-before.