!不同! 之间的总顺序易失变量?

发布于 2024-08-27 02:57:59 字数 847 浏览 3 评论 0原文

考虑以下 Java 代码:

volatile boolean v1 = false;
volatile boolean v2 = false;

//Thread A
v1 = true;
if (v2)
    System.out.println("v2 was true");

//Thread B
v2 = true;
if (v1)
    System.out.println("v1 was true");

如果存在全局可见的易失性访问总顺序,则始终会到达至少一个 println。

Java 标准确实保证了这一点吗?或者像这样的执行是可能的:

A: v1 = true;
B: v2 = true;
A: read v2 = false;
B: read v1 = false;
A: v2 = true becomes visible (after the if)
B: v1 = true becomes visible (after the if)

我只能找到有关访问标准中相同 易失性变量的语句(但我可能会遗漏一些东西)。

“对易失性变量 (§8.3.1.4) v 的写入与任何线程对 v 的所有后续读取进行同步(其中后续是根据同步顺序定义的)。”

http://java.sun.com/ docs/books/jls/third_edition/html/memory.html#17.4.4

谢谢!

Consider the following Java code:

volatile boolean v1 = false;
volatile boolean v2 = false;

//Thread A
v1 = true;
if (v2)
    System.out.println("v2 was true");

//Thread B
v2 = true;
if (v1)
    System.out.println("v1 was true");

If there was a globally visible total order for volatile accesses then at least one println would always be reached.

Is that actually guaranteed by the Java Standard? Or is an execution like this possible:

A: v1 = true;
B: v2 = true;
A: read v2 = false;
B: read v1 = false;
A: v2 = true becomes visible (after the if)
B: v1 = true becomes visible (after the if)

I could only find statements about accesses to the same volatile variable in the Standard (but I might be missing something).

"A write to a volatile variable (§8.3.1.4) v synchronizes-with all subsequent reads of v by any thread (where subsequent is defined according to the synchronization order)."

http://java.sun.com/docs/books/jls/third_edition/html/memory.html#17.4.4

Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

你的心境我的脸 2024-09-03 02:57:59

v1/v2的易失性读/写这4个动作都是同步动作。执行对它们有一个同步顺序,这是一个全序。顺序必须保持每个线程的程序顺序。

这使得推理变得非常容易。显然,至少对于 2 个变量中的 1 个,按照“同步顺序”,对其进行写入的顺序在读取之前进行。因此,写入与读取“同步”。因此,写入“发生在读取之前”。因此,写入对于读取是可见的。

The 4 actions, volatile read/write of v1/v2, are all synchronization actions. An execution has a synchronization order over them, which is a total order. The order must keep the program order of each thread.

That makes reasoning very easy. Obviously at least for 1 of the 2 variables, the write to it is ordered before the read from it, in the 'synchronization order'. Therefore, the write 'synchronizes-with' the read. Therefore, the write 'happens-before' the read. Therefore, the write is visible to the read.

野生奥特曼 2024-09-03 02:57:59

我认为这句话比你意识到的更能回答你的问题。

当线程 A 尝试读取变量时,第 2 行中线程 Bv2 的写入被线程 A“看到”。

我将引用的关键部分加粗:

“对易失性变量 (§8.3.1.4) v 的写入与任何线程对 v 的所有后续读取同步 ...”

I think the quote answers your question more than you realize it does.

The write to v2 by thread B in line #2 is "seen" by thread A when it attempts to read the variable.

I've bolded the key part of the quote:

"A write to a volatile variable (§8.3.1.4) v synchronizes with all subsequent reads of v by any thread ..."

拥醉 2024-09-03 02:57:59

由于 v2易失性,因此执行中的第三行是不可能的。

如果 v2 不是 易失性,则线程 A 可以看到 v2 的本地缓存副本,但该副本仍为 false

然而,由于 v2 是易失性的,因此每次读取都将直接进入主内存,因此将看到最近写入的值。

也就是说,我不认为对不同全局变量的访问之间存在任何特定的顺序保证,但我也不认为这对您的示例有影响。

The third line in your execution is not possible, due to the fact that v2 is volatile.

If v2 were not volatile, thread A could see a locally-cached copy of v2 that was still false.

Since v2 is volatile, however, every read will go directly to main memory, and will thus see the most recently-written value.

That said, I don't believe there are any specific ordering guarantees between accesses to different global variables, but I also don't believe it makes a difference in your example.

痴梦一场 2024-09-03 02:57:59

Java 中的易失性变量始终是顺序一致的。因此它们的执行与所有易失性加载和存储的顺序执行一致。在此顺序执行中,所有加载和存储都有一个总顺序(因此在不同地址上加载和存储;而不仅仅是在单个地址上)。

所以你的例子中的执行是不允许的。

Volatile variables in Java are always sequential consistent. So their execution is consistent with a sequential execution of all volatile loads and stores. In this sequential execution there is a total order over all loads and stores (so loads and stores over different addresses; not just over a single address).

So the execution in your example is not allowed.

为人所爱 2024-09-03 02:57:59

嗯...根据 volatile 的定义,如果 B 将 v2 设置为 true,那么 A 就无法将其读取为 false。

易失性使数据类型和引用在执行单个操作时线程化时按预期工作(因此 ++ 和 -- 不起作用!)

Well...by the definition of volatile if v2 was set to true by B, then A can't read it as false.

volatile makes data types and references work as expected when threading when doing single opeartions (so ++ and -- don't work!)

£烟消云散 2024-09-03 02:57:59

简而言之:至少会打印一次,因为两个易失性操作不能重新排序。

我不知道规范中在哪里写到,但 Doug Lea 网站上有一个表,哪些操作可以重新排序,哪些操作不能重新排序。 (http://gee.cs.oswego.edu/dl/jmm/cookbook。 html


这种情况是不可能的,因为读取是在线程启动之前进行初始化

错误!

A: v1 = true;
B: v2 = true; 
A: read v2 = false; // initialization happens before thread start
B: read v1 = false; // initialization happens before thread start

如果仅在这种情况下,您的情况就有可能,但是< /strong> 这是不可能的,因为 v2 和 v1 是易失性的,写入 v1 必须在读取 v2 之前 并且 写入 v2 必须在读取 v1 之前

错误!

volatile boolean v1 = false;
volatile boolean v2 = false;

//Thread A
if (v2)    //read v2
   System.out.println("v2 was true");
v1 = true; //write to v1

//Thread B
if (v1)    //read v1
    System.out.println("v1 was true");
v2 = true; //write v2

Briefly: At least once will be printed, because the two volatile operations can not be reordered.

I do not know where it is written about in the specification, but on the Doug Lea site have a table which operations can reorder and what does not. ( http://gee.cs.oswego.edu/dl/jmm/cookbook.html )


This situation is not possible, because read is initialization happens before thread start

WRONG!

A: v1 = true;
B: v2 = true; 
A: read v2 = false; // initialization happens before thread start
B: read v1 = false; // initialization happens before thread start

You situation possible if only in this situation, but it is not possible because v2 and v1 is volatile and write to v1 must be before read v2 AND write to v2 must be before read v1

WRONG!

volatile boolean v1 = false;
volatile boolean v2 = false;

//Thread A
if (v2)    //read v2
   System.out.println("v2 was true");
v1 = true; //write to v1

//Thread B
if (v1)    //read v1
    System.out.println("v1 was true");
v2 = true; //write v2
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文