小编Nik*_*ski的帖子

易失性变量和从主存储器刷新/读取

官方说明说,那

写入易失性字段与监视器释放具有相同的记忆效应,从易失性字段读取具有与监视器获取相同的记忆效应.

实际上,易失性的语义已大大加强,几乎达到了同步的程度.出于可见性的目的,每次读取或写入易失性字段的行为类似于"半"同步.

这里开始.

这是否意味着,对volatile变量的任何写入都会使执行线程将其缓存刷新到主内存中,并且每次从volatile字段读取都会使线程从主内存重新读取其变量?

我问,因为同一文本包含此声明

重要说明:请注意,两个线程都必须访问相同的volatile变量才能正确设置before-before关系.情况并非如此,线程A在写入易失性字段f时可见的所有内容在读取易失性字段g后变为线程B可见.释放和获取必须"匹配"(即,在相同的易失性字段上执行)以具有正确的语义.

这句话让我很困惑.我知道对于使用synchronized语句定期锁定获取和释放不是这样 - 如果某个线程释放任何监视器,那么它所做的所有更改都会明显地变为所有其他线程(更新:实际上不是真的 - 请注意最佳答案).在stackoverflow上甚至有一个关于它问题.然而据说无论出于何种原因,情况并非如此.我无法想象发生在事先保证的任何实现,它不会使其他线程看到更改,这些线程不会读取相同的volatile变量.至少想象一个实现,它与前两个引号并不矛盾.

此外,在发布这个问题之前,我做了一些研究,例如这篇文章,其中包含这个句子

执行这些指令后,所有其他线程都可以通过缓存子系统或主内存看到所有写入.

提到的指令是在写入易失性字段时发生的指令.

那重要的音符应该是什么意思?或者我错过了什么?或许这个说明是完全错误的?

回答?

在进行了一些更多的研究后,我只能在官方文档中找到关于volatile字段及其对非易失性字段变化的影响的声明:

使用volatile变量可降低内存一致性错误的风险,因为对volatile变量的任何写入都会建立与之后读取同一变量的先发生关系.这意味着对volatile变量的更改始终对其他线程可见.更重要的是,它还意味着当线程读取volatile变量时,它不仅会看到volatile的最新更改,还会看到导致更改的代码的副作用.

这里开始.

我不知道这是否足以得出结论,这种情况发生在关系只保证读取相同的volatile的线程之前.所以现在我只能总结一下结果是不确定的.

但实际上我建议考虑线程A在写入volatile字段时所做的更改,B只有当线程B读取相同的volatile字段时,才能保证线程可见.官方消息来源的上述引言强烈暗示.

java multithreading synchronization jvm volatile

7
推荐指数
1
解决办法
152
查看次数

Java volatile 重新排序预防范围

对 volatile 字段的写入和读取分别防止在 volatile 字段之前和之后重新排序读/写。写入 volatile 变量之前的变量读/写不能重新排序在它之后发生,而从 volatile 变量读取之后的读/写不能重新排序在它之前发生。但这项禁令的范围是什么?据我了解, volatile 变量只能防止在使用它的块内重新排序,对吗?

为了清楚起见,让我举一个具体的例子。假设我们有这样的代码:

int i,j,k;
volatile int l;
boolean flag = true;

void someMethod() {
    int i = 1;
    if (flag) {
        j = 2;
    }
    if (flag) {
        k = 3;
        l = 4;
    }
}
Run Code Online (Sandbox Code Playgroud)

显然,write tol将阻止 write tok重新排序,但它会阻止重新排序写入ij关于l? 换句话说,可以写入ij在写入之后发生l吗?

更新 1

感谢大家花时间回答我的问题 - 我很感激。问题是你回答了错误的问题。我的问题是关于范围,而不是关于基本概念。问题基本上是编译器在代码中保证“发生在之前”与 volatile 字段的关系有多远。显然编译器可以保证在同一个代码块内,但是封闭块和对等块呢 - 这就是我的问题。@Stephen C 说,volatile 保证发生在整个方法主体内部的行为之前,即使在封闭块中,但我找不到任何确认。他说得对吗,有什么地方可以确认吗?

让我再举一个关于范围界定的具体例子来澄清事情: …

java concurrency multithreading volatile

4
推荐指数
1
解决办法
797
查看次数