Java 多个可变变量之间的同步

Java 多个可变变量之间的同步,java,concurrency,volatile,Java,Concurrency,Volatile,鉴于以下代码: public class Test { private volatile boolean a; private volatile boolean b; private void one () { a = true; System.out.println (b); } private void two () { b = true; System.out.println (a); } public static v

鉴于以下代码:

public class Test {

  private volatile boolean a;

  private volatile boolean b;

  private void one () {
    a = true;
    System.out.println (b);
  }

  private void two () {
    b = true;
    System.out.println (a);
  }

  public static void main (String[] args) throws Exception {
    Test s = new Test ();
    Thread one = new Thread (s::one);
    Thread two = new Thread (s::two);
    one.start ();
    two.start ();
    one.join ();
    two.join ();
  }

}
是否保证(在Java内存模型下)至少有一个线程打印
true

我知道对易失性变量的写入和看到更新值的读取之间存在“先发生后发生”的关系,但我觉得没有一个线程可以看到更新值,尽管我无法做到这一点。

是的,这是有保证的

为了证明这一点,假设线程1打印
false
,而不失一般性。由于
b
是易变的,这意味着线程1在线程2写入
b
之前执行打印。但是如果是这种情况,那么当线程2执行自己的打印时,
a
必须已经被线程1设置为
true

请注意,在写入之前,无法按照以下要求对打印进行重新排序:


  • 如果x和y是同一线程的动作,并且x在程序顺序中位于y之前,那么hb(x,y)[x发生在y之前]
此外,对
a
b
的写入将立即对另一个线程可见:

  • volatile
    字段()的写入发生在随后每次读取该字段之前

我认为它必须至少打印一个
true
,尽管我实际上不会编写这样的代码。如果
one
打印
false
,则必须已执行
a=true
,因此另一个线程必须打印
true
。如果两个线程交错,它们都可以打印
true
,但我看不到一个路径可以同时打印
false
。我看不到这里的冲突。这两种方法都无法锁定,因为易失性变量将被简单地更新和释放,例如,一旦
b=true
完成,它将释放b上的锁,而不是在等待a被释放时保留它。我认为您的问题可能会得到回答。这不是背负。我认为这里的关键是
println
是否可以在volatile赋值之上重新排序,我认为答案是“否”。这就是我要说的。问题是,程序顺序是有保证的,只允许不违反程序顺序相同结果的重新排序。因为在这里重新排序会产生不同的结果,我认为这是不允许的。不过,我想在内存模型中找到一个更明确的规则@AndyTurner你能澄清17.4.5中的哪一位表示它们不能被重新排序吗?@AndyTurner只是加了一个引号。“对易失性字段(§8.3.1.4)的写入发生在该字段的每次后续读取之前。”这并没有说明对字段的写入发生在读取另一个字段之前。同样在17.4.5中:“需要注意的是,两个动作之间的“发生在之前”关系的存在并不一定意味着它们必须在实现中以该顺序发生。”“如果x和y是同一线程的动作,并且x在程序顺序中位于y之前,那么hb(x,y)[x发生在y之前]。”我想这就是我遗漏的部分。