0

今、私たちは持っています

Load A
StoreStore
Store B

実際の実行順序は次のようになる可能性はありますか

StoreStore
Store B
Load A

可能であれば、 に違反していると思われる状況を説明する方法The Java volatile Happens-Before Guarantee

私の知る限り、揮発性セマンティックは、次の JMM メモリバリア追加戦略を使用して実装されています

insert a StoreStore before volatile variable write operation
insert a StoreLoad after volatile variable write operation
insert a LoadLoad after volatile variable read operation
insert a LoadStore after volatile variable read operation

次のように 2 つの Java スレッドがあるとします。

スレッド 1

Load A
StoreStore
Store volatile B

スレッド 2

Load volatile B
Load C

「The Java volatile Happens-Before Guarantee」によれば、<code>Load Aは afterのLoad C場合に発生する必要がありますが、「after Store volatile B」に並べ替えることができる場合、どのように保証しますか?Load volatile BStore volatile BLoad ALoad A is before Load C

4

2 に答える 2

0

This is answering just the updated part of your Question.

First of all, the example you have presented is not Java code. Therefore we cannot apply JMM reasoning to it. (Just so that we are clear about this.)

If you want to understand how Java code behaves, forget about memory barriers. The Java Memory Model tells you everything that you need to do in order for the memory reads and writes to have guaranteed behavior. And everything you need know in order to reason about (correct) behavior. So:

  • Write your Java code
  • Analyze the code to ensure that there are proper happens before chains in all cases where on thread needs to read a value written by another thread.
  • Leave the problem of compiling your (correct) Java code to machine instructions to the compiler.

Looking at the sequences of pseudo-instructions in your example, they don't make much sense. I don't think that a real Java compiler would (internally) use barriers like that when compiling real Java code. Rather, I think there would be a StoreLoad memory barrier after each volatile write and before each volatile read.

Lets consider some real Java code snippets:

public int a;
public volatile int b;

// thread "one"
{
  a = 1;
  b = 2;
}

// thread "two"
{ 
  if (b == 2) {
      print(a);
  }
}

Now assuming that the code in thread "two" is executed after thread "one", there will be a happens-before chain like this:

  • a = 1 happens-before b = 2
  • b = 2 happens-before b == 2
  • b == 2 happens-before print(a)

Unless there is some other code involved, the happens-before chain means that thread "two" will print "1".

Note:

  1. It is not necessary to consider the memory barriers that the compiler uses when compiling the code.
  2. The barriers are implementation specific and internal to the compiler.
  3. If you look at the native code you won't see memory barriers per se. You will see native instructions that have the required semantics to ensure that the (hidden) memory barrier is present.
于 2019-10-12T04:31:40.330 に答える