Search code examples
javamultithreadingconcurrencyjava-memory-model

Clarification on single writer


I have a couple of clarifications on the statements below(source - https://mechanical-sympathy.blogspot.in/2011/09/single-writer-principle.html):

'x86/x64 have a memory model, whereby load/store memory operations have preserved order, thus memory barriers are not required if you adhere strictly to the single writer principle.

On x86/x64 "loads can be re-ordered with older stores" according to the memory model so memory barriers are required when multiple threads mutate the same data across cores. '

Does this mean that :
1. Within a single core , load/store memory operations are always in order?
So a single writer thread (and multiple reader threads ) on a single core system would not need to 'synchronize' to resolve visibility issues?
2. For multiple cores, loads can be re-ordered with stores initiated from other cores ?
So a single writer thread ( and multiple reader threads running on other cores ) would not need to 'synchronize' to resolve visibility issues (as there wont be any stores)?

So,if we strictly maintain a single writer - we can actually do away with the practice of using 'synchronized' on both reads and writes in primitive locks. We can actually do away with 'synchronized' completely?


Solution

  • Within a single core, it doesn’t matter whether the memory access is done in-order or out-of-order. If there is a single core, it will always perceive consistent values, as read requests will be served by the same cache holding not-yet-written data.

    However, that is irrelevant for Java programs, as the Java Memory Model, part of the Java Language Specification, doesn’t make such guarantees for multi-threaded programs. In fact, the term “memory barrier” doesn’t appear within the specification at all.

    What you have to realize, is, that the Java code you have written, will not be the x86/x64 code the CPU will execute. The optimized native code won’t be anything like your source code. One fundamental part of the code optimization is to eliminate redundant reads and writes or even conditional code parts, under the assumption that values do not spuriously change in-between, which is always correct for single threaded execution.

    This optimized code will produce inconsistent results, if the underlying assumptions are invalidated due to multi-threaded manipulation without proper thread safe constructs. This is an accepted inconsistency, within the specification, as a memory model enforcing consistent results at all costs would result in dramatically poor performance. The thread safe constructs, like synchronization or volatile writes and reads, do not only tell the JVM where to insert memory barriers, if the underlying architecture requires it, but also, where and how to restrict the code optimizations.

    This is the reason why a) proper thread safe constructs are needed when manipulating mutable shared state and b) these constructs may have performance penalties, even if there are no memory barriers needed at the CPU/hardware level.