挥发性背驮式.这对于visiblity来说足够了吗?

tem*_*per 22 java synchronization volatile

这是关于不稳定的背驮式.目的:我希望达到轻量级vars visibilty.a_b_c的一致性并不重要.我有一堆vars,我不想让它们都变得不稳定.

这段代码是否安全?

class A {
    public int a, b, c;
    volatile int sync;

    public void setup() {
        a = 2;
        b = 3;
        c = 4;
    }

    public void sync() {
        sync++;
    }
}

final static A aaa = new A();

Thread0:
aaa.setup();
end

Thread1:
for(;;) {aaa.sync(); logic with aaa.a, aaa.b, aaa.c}

Thread2:
for(;;) {aaa.sync(); logic with aaa.a, aaa.b, aaa.c}
Run Code Online (Sandbox Code Playgroud)

Ada*_*man 33

Java Memory Model定义了before-before关系,它具有以下属性(以及其他属性):

  • "线程中的每个操作都发生在 - 在程序顺序中稍后出现的该线程中的每个操作之前"(程序顺序规则)
  • "对易失性字段的写入发生在每次后续读取相同的易失性之前"(volatile变量规则)

这两个属性以及先发生关系的传递性意味着可见性保证OP以下列方式寻求:

  1. 写于a螺纹1 之前发生一个写sync在调用sync()在线程1(程序顺序规则).
  2. 到写sync在调用sync()在线程1 之前发生的读出,以sync在呼叫到sync在螺纹2(易失性可变规则).
  3. 从读sync在调用sync()中的线程2 之前发生的读取距离a在2线(程序顺序规则).

这意味着,这个问题的答案是肯定的,即呼吁sync()在线程1每次迭代和2,确保变更的可视性a,b并且c给其他线程(或多个).请注意,这仅确保可见性.不存在互斥保证,因此所有不变量都具有约束力a,b并且c可能会受到违反.

另请参阅Java理论与实践:修复Java内存模型,第2部分.特别是"挥发性新保证"一节

在新的内存模型下,当线程A写入易失性变量V,并且线程B从V读取时,在写入V时对A可见的任何变量值现在都保证对B可见.

  • @PhilippWendler这两个规则意味着可以通过以下方式看到线程1中对线程2进行的`a`,`b`和`c`的更改:在线程1中更改为`a` _之前 - 写入`sync`在线程1(规则1)中的`sync()`的后续调用中,在线程2(规则2)中对`sync`的调用中_happens-before_读取`sync`之前_happens-before_读取`a `在主题2中(同样,规则1). (2认同)
  • @PhilippWendler 另请参阅我链接到的文章,特别是“易失性的新保证”部分。另一则相关引用:“在新的内存模型下,当线程 A 写入易失性变量 V,而线程 B 读取 V 时,在写入 V 时 A 可见的任何变量值现在都保证可见到B。” (2认同)

Tud*_*dor 5

使用just绝对不能在线程之间增加值volatile。这只能确保每个线程获取最新值,而不是确保增量是原子的,因为在汇编器级别,++实际上是可以交错的几条指令。

您应该使用AtomicInteger快速原子增量。

编辑:再次阅读所需的内容实际上是一个内存围栏。Java没有内存围栏指令,但是您可以对内存围栏“副作用”使用锁定。在这种情况下,请声明sync方法同步以引入隐式篱笆:

void synchronized sync() {
    sync++;
}
Run Code Online (Sandbox Code Playgroud)