what is the reasoning behind volatile semantics in Java and C#

后端 未结 2 1495
臣服心动
臣服心动 2021-02-03 10:24

Both C# and Java define that
* volatile reads have acquire semantics
* volatile writes have release semantics

My

相关标签:
2条回答
  • 2021-02-03 10:59

    The reasoning behind the volatile semantic is rooted in the Java Memory Model, which is specified in terms of actions:

    • reads and writes to variables
    • locks and unlocks of monitors
    • starting and joining with threads

    The Java Memory Model defines a partial ordering called happens-before for the actions which can occur in a Java program. Normally there is no guarantee, that threads can see the results of each other actions.

    Let's say you have two actions A and B. In order to guarantee, that a thread executing action B can see the results of action A, there must be a happens-before relationship between A and B. If not, the JVM is free to reorder them as it likes.

    A program which is not correctly synchronized might have data races. A data race occurs, when a variable is read by > 1 threads and written by >= 1 thread(s), but the read and write actions are not ordered through the happens-before ordering.

    Hence, a correctly synchronized program has no data races, and all actions within the program happen in a fixed order.

    So actions are generally only partially ordered, but there is also a total order between:

    • lock acquisition and release
    • reads and writes to volatile variables

    These actions are totally ordered.

    This makes it sensible to describe happens-before in terms of "subsequent" lock acquisitions and reads of volatile variables.

    Regarding your questions:

    1. With the happen-before relationship you have an alternative definition of volatile
    2. Reversing the order would not make sense to the definition above, especially since there is a total order involved.

    happens-before

    This illustrates the happens-before relation when two threads synchronize using a common lock. All the actions within thread A are ordered by the program order rule, as are the actions within thread B. Because A releases lock M and B subsequently acquires M, all the actions in A before releasing the lock are therefore ordered before the actions in B after acquiring the lock. When two threads synchronize on different locks, we can't say anything about the ordering of actions between themthere is no happens-before relation between the actions in the two threads.

    Source: Java Concurrency in Practice

    0 讨论(0)
  • 2021-02-03 11:06

    The power of the acquire/release semantics isn't so much about how soon other threads see the newly written value of the volatile field itself, but rather in the way volatile operations establish a happens-before relation across different threads. If a thread A reads a volatile field and sees a value that was written to that field in another thread B then thread A is also guaranteed to see values written to other (not necessarily volatile) variables by thread B before the point where it did the volatile write. This looks like cache flushing but only from the point of view of a thread that read the volatile, other threads that don't touch the volatile field have no ordering guarantees with respect to B and might see some of its earlier non-volatile writes but not others if the compiler/JIT is so inclined.

    Monitor acquires/releases are similarly characterised by their induced happens-before relation - actions by one thread before a release of a monitor are guaranteed to be visible after a subsequent acquire of the same monitor by another thread. Volatiles give you the same ordering guarantees as monitor synchronisation but without blocking.

    0 讨论(0)
提交回复
热议问题