ListBuffer is used as List.newBuilder and its toList serves as the implementation for builder’s result(). Before returning the head element of the underlying list to the application, it calls releaseFence(). This means that whatever val or var the returned List is assigned to, lets call it x, the assignment will happen after all mutations performed via the builder/buffer. But it’s not good enough, is it? Because any thread reading (‘loading’) x and x.tail can have the load of x.tail reordered before the load of x. Unless JVM implements the dereferencing ordering (any value read through a pointer is at least as new as the pointer value), and I don’t think it does, it means that the load of x.tail can actually happen in real time before the call to releaseFence() and thus potentially read stale data.
Now, I admit I don’t feel entirely comfortable with memory fences, but this seems like the most basic use case and goes against what all primers on fences seem to show. What am I missing?
Can you write an example of the case that you’re worried about? It’ll make it easier to decide if all the necessary happens-before of the Java Memory Model are in place.