Why is releaseFence() in ListBuffer.toList enough without an acquireFence() in all threads using the list?

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.

What’s your basis for thinking that?

I’m too lazy to answer the question but not too lazy to click thru the issues

2018 still feels like last year because this year is still 2019 right before the pandemic.

OTOH, retronym fiddling with releaseFence feels like a long, long time ago. Now I’m going to start singing bye, bye Miss American pie.

1 Like

retronym’s branch is called “unsafe-undead”. I can’t wait for the Netflix series.

Also, “but February made me shiver with every paper I’d deliver.” That song is so kitschy! I’m mad it’s going through my head now.

1 Like