Java Unsafe.storeFence() documentation wrong?
Asked Answered
B

2

11

Java 8 has added three fences to sun.misc.Unsafe.

I feel confused after I read their documentation.

So, I searched the web, and found this link.

According to the page above, I believe these methods add almost nothing in practice. Correct me if I'm wrong, roughly speaking, loadFence(), storeFence() and fullFence() correspond to volatile read, lazy write and volatile write respectively, although technically these fences are stronger than volatile variables. So loadFence() is an acquire fence, and storeFence() is a release fence, and fullFence() is full fence.

But then the documentation for storeFence() looks strange.

It says,

/**
 * Ensures lack of reordering of stores before the fence
 * with loads or stores after the fence.
 */
void storeFence();

That doesn't look like a release fence. How is it supposed to be used? Shouldn't it be

/**
 * Ensures lack of reordering of loads or stores before the fence
 * with stores after the fence.
 */
void storeFence();

I assume before means earlier and after means later.

EDIT

I don't mean "we don't use them in usual development" when I say these "fences add nothing in practice".

I mean, even without these methods in Unsafe, we can get these "fences". If I am correct, in practice, reading a dummy volatile has the effect of loadFence(), and writing a dummy volatile has the effect of fullFence(), and unsafe.putOrderedXXX() (or AtomicInteger.lazySet()) has the effect of storeFence().

They may have subtle difference, but in current implementation, they are exchangeable. (Seems implied by the link)

That is what I mean by "they add nothing new".

ANOTHER EDIT

This is already fixed.

See https://bugs.openjdk.java.net/browse/JDK-8038978

Thanks @john-vint

Boding answered 2/6, 2015 at 15:42 Comment(1)
An implementation link which might be helpful.Unhappy
K
6

There is actually a diff for this in JDK9. There were similar questions that were asked and clarified:

http://hg.openjdk.java.net/jdk9/jdk9/jdk/rev/84e19392365e

      /**
!      * Ensures that loads before the fence will not be reordered with loads and
!      * stores after the fence; a "LoadLoad plus LoadStore barrier".
!      *
!      * Corresponds to C11 atomic_thread_fence(memory_order_acquire)
!      * (an "acquire fence").
!      *
!      * A pure LoadLoad fence is not provided, since the addition of LoadStore
!      * is almost always desired, and most current hardware instructions that
!      * provide a LoadLoad barrier also provide a LoadStore barrier for free.
       * @since 1.8
       */
      public native void loadFence();

      /**
!      * Ensures that loads and stores before the fence will not be reordered with
!      * stores after the fence; a "StoreStore plus LoadStore barrier".
!      *
!      * Corresponds to C11 atomic_thread_fence(memory_order_release)
!      * (a "release fence").
!      *
!      * A pure StoreStore fence is not provided, since the addition of LoadStore
!      * is almost always desired, and most current hardware instructions that
!      * provide a StoreStore barrier also provide a LoadStore barrier for free.
       * @since 1.8
       */
      public native void storeFence();

      /**
!      * Ensures that loads and stores before the fence will not be reordered
!      * with loads and stores after the fence.  Implies the effects of both
!      * loadFence() and storeFence(), and in addition, the effect of a StoreLoad
!      * barrier.
!      *
!      * Corresponds to C11 atomic_thread_fence(memory_order_seq_cst).
       * @since 1.8
       */
      public native void fullFence();
Kissiah answered 2/6, 2015 at 16:47 Comment(4)
So it is already clarified. I feel a little surprised they bother to add so many words, provided Java 9 is supposed to make internal APIs unusable.Boding
Do these fences only prevent reordering of reads and writes or do they also drain the load/store buffers?Nihility
They are used mostly for reordering and the JMM/CPU doesn't have to drain the buffers. For instance, if you put a fullFence before and after a write while adding a loadFence before and after a read to the written variable, you can still observe out of date reads.Kissiah
shipilev.net/blog/2016/close-encounters-of-jmm-kind/…Kissiah
A
0

I believe these methods add almost nothing in practice.

Correct, they wouldn't add anything in 99.9% of applications. It is only need in very specific cases would you need to call this method directly rather than use a higher level construct.

volatile read, lazy write and volatile write respectively,

I read it as "volatile read, volatile write, volatile write and read" There doesn't appear to be a lazy/ordered write fence.

loadFence() is an acquire fence, and storeFence() is a release fence,

I don't believe these translates to an acquire/release semantics. They are more basic than that. There is no state change in these methods for example. acquire/release requires an atomic operation such as a compareAndSet which is another Unsafe method.

Autrey answered 2/6, 2015 at 15:52 Comment(5)
I mean something like "AtomicInteger.lazySet()" when I say lazy writeBoding
I don't understand why you say they don't translate to acquire/release semantics. The doc for loadFence() says "Ensures lack of reordering of loads before the fence with loads or stores after the fence.", that sounds almost the definition of an acquire barrier.Boding
@Boding what do you mean by "acquire barrier"? These neither reads nor writes so what is it acquiring or releasing? I assume you are not talking about Semaphore.acquire/release.Autrey
"they don't do anything in 99.9% of use cases" - you are propagating the no op myth. They do what they say, which is prevent re-ordering. The "no op" is purely on the hardware level for most hardwares, but the effect on compilation is significant.Periodical
@NitsanWakart you are right, my answer was poorly worded and open to this misinterpretation. I have rewritten it now.Autrey

© 2022 - 2024 — McMap. All rights reserved.