The process of creation of some of Scala
immutable collections, most notably List
, is mutable. In 2.13
the concurrency issues were addressed by adding a release fence basically to every builder. A release fence prevents memory writes coming after the fence from being reordered before the fence - so, if you have a 'final write' (such as 'payload_ready' in many examples), it means that anything you wrote (and read) before is commited to shared memory (or at least visible to other threads). When I was reading on fences, I came under impression that a release fence needs a matching acquire fence in the code reading the data commited by the other thread. I accepted it as it coincided with an old adage that no synchronisation will work if it happens only at one site (vide the famous 'double-check locking/singleton pattern is broken' warning). I know that Java's (and C++) memory model is more abstract than any contemporary physical architecture, so some aspects of it are irrelevant.
I freely admit that I have no experience with such low-level control as memory barriers, so I do not feel comfortable with using them. In particular, I can't see how writes being reordered after a release fence (which, as I understand, is still possible) is any different from writes from after the fence actually happening before it, the latter being forbidden. The fence location is irrelevant, what matters is the happens-before relationship. I would like to understand why the lone release fence is enough, or ''when'' it is enough, and when in that case an acquire fence will still be needed.