【问题标题】:Volatile variables and other variables易变变量和其他变量
【发布时间】:2012-09-08 10:36:14
【问题描述】:

以下来自经典Concurency in Practice

当线程 A 写入 volatile 变量,随后线程 B 读取相同的变量,all 变量的值 在写入 volatile 变量之前对 A 可见,变为可见 读取 volatile 变量后到 B。

我不确定我是否能真正理解这句话。例如,在这种情况下,所有变量是什么意思?这是否意味着使用volatile 对使用非易失性变量也有副作用?
在我看来,这句话有一些我无法理解的微妙含义。
有什么帮助吗?

【问题讨论】:

    标签: java multithreading concurrency volatile memory-visibility


    【解决方案1】:

    你的问题的答案在JLS #17.4.5:

    对 volatile 字段(第 8.3.1.4 节)的写入发生在对该字段的每次后续读取之前。

    所以如果在一个线程中你有

    aNonVolatileVariable = 2 //w1
    aVolatileVariable = 5 //w2
    

    随后在另一个线程中:

    someVariable = aVolatileVariable //r1
    anotherOne = aNonVolatileVariable //r2
    

    您可以保证anotherOne 将等于 2,即使该变量不是易失性的。所以是的,使用 volatile 对使用非易失性变量也有副作用。

    更详细地说,这是由于 Java 内存模型 (JMM) 在同一部分中提供的另外 2 个保证:线程内顺序和传递性(hb(x,y) 表示 x 发生在 y 之前):

    如果 x 和 y 是同一线程的操作,并且 x 在程序顺序中位于 y 之前,则 hb(x, y)
    [...]
    如果 hb(x, y)hb(y, z),那么 hb(x, z)

    在我的例子中:

    • hb(w1, w2)hb(r1, r2)(线程内语义)
    • hb(w2, r1) 因为 volatile 保证

    所以你可以通过传递性得出结论 hb(w1, r2)

    JMM 保证程序的所有执行都将是顺序一致的(即看起来好像没有重新排序),如果它与之前发生的关系正确同步。所以在这种特定情况下,非易失性读取保证看到非易失性写入的效果。

    【讨论】:

    • 对不起,我看不出这个保证是如何从JSL的声明中得出的。它所说的只是对易失性happens-before的写入是对字段的读取。这是怎么做到的还保证在另一个线程中anotherOne 可见为2?
    • 我了解hb(w1, r2)。到目前为止还可以。但是为什么这里强制要求2 的更新值是可见的?不可能,写发生之前,但读取使用的是缓存值而不是来自w1 的值?这是我无法获得的部分。hb(w1, r2) 的定义是否还包括可见性方面?
    • @Cratylus The JMM guarantees that a program that is correctly synchronized (with happens-before relationships) will be sequentially consistent: “这对程序员来说是一个非常有力的保证。[...] 一旦确定代码正确同步,程序员就不需要担心重新排序会影响他或她的代码。”
    • @Cratylus 在同一部分中 JLS 的另一个引用:“在发生前一致的一组操作中,每次读取都会看到一次写入,而发生前的顺序允许它看到。”
    • 这些评论不是解决了由于重新排序导致的不可见性吗?好的重新排序不会发生,但是在寄存器中缓存值呢?
    【解决方案2】:

    这意味着如果你写入十个非易失性变量并写入一个易失性变量,所有非易失性变量必须在易失性变量之前设置。

    如果您读取 volatile 变量和所有非 volatile 变量,您可以确定不会交换顺序。

    【讨论】:

    • 你在说什么顺序?volatile 变量不能重新排序,好的。所以volatile 变量不应该用非易失性重新排序并最后写入。但是非易失性变量的顺序仍然可以更改,对吧?
    • 在 volatile 变量中设置的值的顺序不能相对于其他变量(volatile 或其他变量)改变,但对于非 volatile 变量可能会发生这种情况。这意味着当您设置一个 volatile 变量时,所有先前设置的值都将被缓存一致,即使它们不是 volatile。
    • 什么是缓存一致性?它们也不会被缓存?
    • 它们将被缓存,但 CPU 确保每个缓存看到相同的值(或会按需请求)每个 Socket 都有多个 2 或 3 级缓存。它们有一个通信总线,以确保它们在需要时相互同步。甚至多个套接字也会进行通信以保持同步,从而避免从主内存中写入/读取值。
    • 但是为什么非易失性变量需要并保证这种同步?仅仅因为它们发生在写入volatile之前出现,它们会受到怎样的影响?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-01-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多