简体   繁体   English

易失性读取是否发生在易失性写入之前?

[英]Is volatile read happens-before volatile write?

I try to understand why this example is a correctly synchronized program: 我试着理解为什么这个例子是一个正确同步的程序:

a - volatile
Thread1:
x=a
Thread2:
a=5

Because there are conflicting accesses (there is a write to and read of a) so in every sequential consistency execution must be happens-before relation between that accesses. 因为存在冲突的访问(存在对a的写入和读取)所以在每个顺序一致性执行中必须发生 - 在该访问之间的关系之前。 Suppose one of sequential execution: 假设一个顺序执行:

1. x=a
2. a=5

Is 1 happens-before 2, why? 1发生在2之前,为什么?

Is 1 happens-before 2, why? 1发生在2之前,为什么?

I'm not 100% sure I understand your question. 我不是100%确定我理解你的问题。

If you have a volatile variable a and one thread is reading from it and another is writing to it, the order of those accesses can be in either order. 如果你有一个volatile变量a ,一个线程正在从中读取而另一个线程正在写入它,那么这些访问的顺序可以是任意顺序。 It is a race condition . 这是一场竞争 What is guaranteed by the JVM and the Java Memory Model (JMM) depends on which operation happens first. JVM和Java内存模型(JMM)保证的内容取决于首先发生的操作。

The write could have just happened and the read sees the updated value. 写入可能刚刚发生,读取看到更新的值。 Or the write could happen after the read. 或者写入可能在读取后发生。 So x could be either 5 or the previous value of a . 因此, x可以是任何5或以前的值a

every sequential consistency execution must be happens-before relation between that accesses 每个顺序一致性执行必须在该访问之间的关系之前发生

I'm not sure what this means so I'll try to be specific. 我不确定这意味着什么所以我会尝试具体。 The "happens before relation" with volatile means that all previous memory writes to a volatile variable prior to a read of the same variable are guaranteed to have finished. volatile发生“在关系之前发生”意味着在读取相同变量之前所有先前的内存写入volatile变量都保证已完成。 But this guarantee in no way explains the timing between the two volatile operations which is subject to the race condition. 但这种保证绝不能解释两种易受竞争条件影响的volatile运营之间的时间安排。 The reader is guaranteed to have seen the write, but only if the write happened before the read. 读者可以保证已经看到了写,但只有当读前写发生。

You might think this is a pretty weak guarantee, but in threads, whose performance is dramatically improved by using local CPU cache, reading the value of a field might come from a cached memory segment instead of central memory. 您可能认为这是一个非常弱的保证,但在线程中,通过使用本地CPU缓存可以显着提高其性能,读取字段的值可能来自缓存的内存段而不是中央内存。 The guarantee is critical to ensure that the local thread memory is invalidated and updated when a volatile read occurs so that threads can share data appropriately. 保证对于确保在发生volatile读取时本地线程内存无效和更新至关重要,以便线程可以适当地共享数据。

Again, the JVM and the JMM guarantee that if you are reading from a volatile field a , then any writes to the same field that have happened before the read, will be seen by it -- the value written will be properly published and visible to the reading thread. 同样,JVM和JMM保证如果您从volatile字段a读取,那么在读取之前发生的对同一字段的任何写入都将被它看到 - 写入的值将被正确发布并且可见阅读线程。 However, this guarantee in no way determines the ordering. 但是,这种保证决不会决定订购。 It doesn't say that the write has to happen before the read. 它并没有说在写入之前必须发生写入。

No, a volatile read before (in synchronization order) a volatile write of the same variable does not necessarily happens-before the volatile write. 不,在易失性写入之前,(同步顺序)之前的易失性读取不一定发生相同变量的易失性写入。

This means they can be in a "data race", because they are "conflicting accesses not ordered by a happens-before relationship". 这意味着他们可以处于“数据竞争”中,因为它们是“冲突的访问,而不是由先发生过的关系命令”。 If that's true pretty much all programs contain data races:) But it's probably a spec bug. 如果这是真的,几乎所有程序都包含数据竞争:)但它可能是一个规范错误。 A volatile read and write should never be considered a data race. 永远不应将易失性读写视为数据竞争。 If all variables in a program are volatile, all executions are trivially sequentially consistent. 如果程序中的所有变量都是易失性的,则所有执行都是顺序一致的。 see http://cs.oswego.edu/pipermail/concurrency-interest/2012-January/008927.html http://cs.oswego.edu/pipermail/concurrency-interest/2012-January/008927.html

Sorry, but you cannot say correctly how the JVM will optimize the code depending on the 'memory model' of the JVM. 抱歉,您无法正确说出JVM如何根据JVM的“内存模型”优化代码。 You have to use the high level tools of Java for defining what you want. 您必须使用Java的高级工具来定义您想要的内容。

So volatile means only that there will be no "inter-thread cache" used for the variables. 所以volatile只意味着没有用于变量的“线程间缓存”。

If you want a stricter order, you have to use synchronized blocks. 如果您想要更严格的订单,则必须使用同步块。

http://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html http://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html

Volatile and happens-before is only useful when the read of the field drives some condition. 易失性和发生之前仅在读取字段驱动某些条件时才有用。 For example: 例如:

volatile int a;
int b =0;
Thread-1:
   b = 5;
   a = 10;
Thread-2
   c = b + a;

In this case there is no happens-before, a can be either 10 or 0 and b can be either 5 or 0, so as a result c could be either 0, 5, 10 or 15. If the read of a implies some other condition then the happens-before is established for instance: 在这种情况下,没有发生 - 之前,a可以是10或0,b可以是5或0,因此结果c可以是0,5,10或15.如果读取a意味着其他一些条件然后发生before-before例如:

int b = 0;
volatile int a = 0;
Thread-1:
   b = 5
   a = 10;
Thread 2: 
   if(a == 10){
      c = b + a;
   }

In this case you will ensure c = 15 because the read of a==10 implies that the write of b = 5 happens-before the write of a = 10 在这种情况下,您将确保C = 15,因为读a==10暗示的写b = 5的之前发生的写a = 10

Edit: Updating addition order as noted the inconsistency by Gray 编辑:更新添加顺序,如灰色所示的不一致

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM