java – 易失性变量,从主内存刷新/读取

官方说明说,那

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可见.官方消息来源的上述引用强烈暗示.

解决方法

你是从一个完全错误的角度看待这个.首先,您引用JLS而不是讨论flush,这将是该规范的实现细节.你需要依赖的绝对唯一的东西是JLS,其他任何事情都可以知道,但不能证明任何形式或形式的规范是对还是错.

而你错误的根本所在:

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.

相关文章

最近看了一下学习资料,感觉进制转换其实还是挺有意思的,尤...
/*HashSet 基本操作 * --set:元素是无序的,存入和取出顺序不...
/*list 基本操作 * * List a=new List(); * 增 * a.add(inde...
/* * 内部类 * */ 1 class OutClass{ 2 //定义外部类的成员变...
集合的操作Iterator、Collection、Set和HashSet关系Iterator...
接口中常量的修饰关键字:public,static,final(常量)函数...