挥发性背驮式。 这对于可见度足够了吗?

这是关于不稳定的捎带。 目的:我想达到轻量级的可视性。 a_b_c的一致性并不重要。 我有一堆变数,我不想让它们全都变动。

这段代码是线程安全的吗?

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}

Java内存模型定义了具有以下属性的发生之前的关系(其中包括):

  • “线程中的每个动作都发生在该线程中稍后以程序顺序执行的每个动作之前”(程序顺序规则)
  • “对易失性字段的写入发生 - 在每次后续读取同一易失性数据之前”(易失性变量规则)
  • 这两个属性以及发生之前关系的传递性意味着可见性保证OP以如下方式寻求:

  • 到写a在线程1的之前发生一个写sync在调用sync()在线程1(程序顺序规则)。
  • 写入到sync在调用sync()在线程1之前发生的读出到sync在呼叫到sync于螺纹2(易失性可变规则)。
  • 从读sync在调用sync()在线程2之前发生从读a在线程2(程序顺序规则)。
  • 这意味着问题的答案是肯定的,即线程1和2中每次迭代中对sync()的调用都确保abc对其他线程的更改可见性。 请注意,这只能确保可见性。 不存在相互排斥的保证,因此可能违反绑定abc所有不变量。

    另请参阅Java理论和实践:修复Java内存模型,第2部分。特别是“易失性的新保证”部分

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


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

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

    编辑 :再读一遍你所需要的实际上是一个记忆围栏。 Java没有内存围栏指令,但是可以使用内存围栏的“副作用”锁定。 在这种情况下,声明同步方法以引入隐式栅栏:

    void synchronized sync() {
        sync++;
    }
    

    来自javadoc:

    监视器的解锁(同步块或方法退出)发生在相同监视器的每个后续锁定(同步块或方法输入)之前。 并且因为发生在before关系是传递性的,所以在解锁之前的线程的所有动作发生在任何线程锁定该监视器之后的所有动作之前。

    写入易失性字段发生 - 在每次后续读取相同字段之前。 写入和读取易失性字段具有与进入和退出监视器类似的内存一致性效果,但不需要互斥锁定。

    所以我认为在这种情况下写入volatile var并不等同于syncronization,并且它不保证会发生 - 在将Thread1中的更改​​的顺序和可见性更改为Thread2之前

    链接地址: http://www.djcxy.com/p/96863.html

    上一篇: Volatile piggyback. Is this enough for visiblity?

    下一篇: Faking a Streaming Response in Django to Avoid Heroku Timeout