[concurrency-interest] The code example in onSpinWait() Javadoc

Roman Leventov leventov.ru at gmail.com
Fri Nov 15 05:04:34 EST 2019


By "half-baked" I meant specifically that the example could be valid but
only under specific conditions, such as core-pinned thread, or backoff
timeout event, etc. However, the "mundane" class and method names which are
chosen ("EventHandler") may mislead users into thinking that spin-loop is a
good go-to strategy to waiting for some conditions/logic executed, instead
of using a synchronization primitive or attaching a listener to a
CompletableFuture/ListeanableFuture if one is involved.

I like Francesco's example because it is self-contained and doesn't need
any backoff, so the complicated discussion of the tradeoffs involved and
conditions which should be accounted for (typical wait time, GC algorithm,
busyness of the system, etc.) could be blissfully omitted.

On Fri, 15 Nov 2019 at 11:05, Francesco Nigro via Concurrency-interest <
concurrency-interest at cs.oswego.edu> wrote:

> Hi Gil,
>
> It's one of the common use cases
>
> :) Although I can say the same I'm not quite sure that is that common and
> your example re LMAX makes it even more clear (not that mine on JCTools is
> better eh!)
> On the other hand, onSpinWait itself is equally uncommon on j.u.c., so I
> take all your points re the existing doc.
>
> Would a more detailed/complicated/opinionated example of a specific
>> backoff flavor would help
>> make the meaning and use of the method more clear, or help point out
>> caveats or pitfalls better?
>
> My (personal) fear is that users will recognize the general busy spin loop
> pattern, thinking that given that the JVM "is able to optmize it" (thanks
> to help of unicorns and rainbows too) and
> making it a much more attractive pairs of scissors to play with then
> before :)
>
>
> Il giorno ven 15 nov 2019 alle ore 06:38 Gil Tene <gil at azul.com> ha
> scritto:
>
>> I guess I'm missing something about the starting point in this thread.
>> What do you find "half baked"
>> about the actual example in the Javadoc? It's one of the common use cases
>> (with no time-based
>> backoffs) in various applications (ones that e.g. dedicate a spinning
>> thread on a dedicated core).
>>
>> E.g.
>> https://github.com/LMAX-Exchange/disruptor/blob/5764f3b01faab603322c61cede957b7e79f58c8b/src/main/java/com/lmax/disruptor/BusySpinWaitStrategy.java
>>
>> There are obviously additional common variants, some of which include
>> backoff mechanisms
>> (time based, count based, phase of moon based, etc.), but IMO there is no
>> "right way" to do this,
>> and a no-backoff use case is just as valid (and maybe even common) as one
>> that includes a
>> backoff. The code carefully avoids spelling out how
>> "eventNotificationNotReceived" is determined.
>> Hey, the event may even be a backoff timeout...
>>
>> Would a more detailed/complicated/opinionated example of a specific
>> backoff flavor would help
>> make the meaning and use of the method more clear, or help point out
>> caveats or pitfalls better?
>>
>> > On Nov 14, 2019, at 2:28 PM, Francesco Nigro via Concurrency-interest <
>> concurrency-interest at cs.oswego.edu> wrote:
>> >
>> > Gil Tene* Android typo error
>> >
>> > Il gio 14 nov 2019, 23:28 Francesco Nigro <nigro.fra at gmail.com> ha
>> scritto:
>> > I would like to hear the opinion of Gil Gene about it too: AFAIK he was
>> the one (or one of many?) that has proposed it to be included in
>> http://openjdk.java.net/jeps/285
>> >
>> > Il gio 14 nov 2019, 23:22 Francesco Nigro <nigro.fra at gmail.com> ha
>> scritto:
>> > Beside being more complex?
>> > Not much I admit :)
>> > But IMO awaiting with no algorithmical indication of the duration of
>> the wait (like in the javadoc) and awaiting for a finite amount of "time" a
>> condition that will be true at some point, is a better example where to
>> apply onSpinWait, although is not technically incorrect to use it for
>> "blind" spin loop as well.
>> > Maybe is just a subtle difference, but I won't encourage users to
>> blindly spin loop on conditions and just use onSpinWait to save the day..
>> probably I'm worried too much for something very simple and unavoidable; as
>> @roman has suggested, probably no example is better then one that is a
>> superclass of all the possible best cases.
>> >
>> >
>> > Il gio 14 nov 2019, 22:51 Alex Otenko <oleksandr.otenko at gmail.com> ha
>> scritto:
>> > What's the difference between this example and what's in javadocs?
>> >
>> > Alex
>> >
>> > On Thu, 14 Nov 2019, 16:29 Francesco Nigro via Concurrency-interest, <
>> concurrency-interest at cs.oswego.edu> wrote:
>> > Totally right, sorry again (writing by phone is a terrible idea :( ):
>> > yes , poll should  use  "o = this.obj".
>> >
>> > > Can we get rid of "done"?  Since offerOnce() does not allow null,
>> then having the done flag does not seem to help anything.
>> > Absolutely yes: I've prepared this as a "simplified" (and wrong due to
>> the hurry, sorry for that) version of what we do on many queues in JCtools,
>> > that's why it contains some unnecessary bits as you've rightly pointed
>> out.
>> > Code that is spin awaiting on a condition, sure that it will happen at
>> some point in the future, is something that could help to understand the
>> rare cases
>> > where using onSpinWait could be beneficial IMO.
>> >
>> >
>> >
>> > Il giorno gio 14 nov 2019 alle ore 17:18 Nathan and Ila Reynolds <
>> nathanila at gmail.com> ha scritto:
>> > In poll(), should "this.obj = o" be "o = this.obj"?  Without this
>> change, it seems poll() could spin forever.
>> >
>> > Should "poll" be renamed to "take" since the method could block until a
>> value is available?
>> >
>> > Can we get rid of "done"?  Since offerOnce() does not allow null, then
>> having the done flag does not seem to help anything.
>> >
>> > Is the compiler and execution engine in my head misinterpreting and
>> mis-executing the code?
>> >
>> > Here is the code with my suggested changes.
>> >
>> >    volatile E obj = null;
>> >
>> >    public void offerOnce(E o) {
>> >       Objects.checkNonNull(o);
>> >       this.obj = o;
>> >    }
>> >
>> >   public boolean isDone() {
>> >        return obj != null;
>> >   }
>> >
>> >    public E take() {
>> >       E o;
>> >
>> >       while (true) {
>> >          o = obj;
>> >
>> >          if (o != null)
>> >             return o;
>> >
>> >          java.lang.Thread.onSpinWait();
>> >       }
>> >    }
>> > -Nathan
>> > On 11/14/2019 8:54 AM, Francesco Nigro wrote:
>> >> Sorry I've written on the email text, I forgot an important part, let
>> me write it properly:
>> >>
>> >>    volatile E obj = null;
>> >>    volatile boolean done = false;
>> >>
>> >>    public void offerOnce(E o) {
>> >>       Objects.checkNonNull(o);
>> >>       this.done = true;
>> >>       this.obj = o;
>> >>    }
>> >>
>> >>   public boolean isDone() {
>> >>        return done;
>> >>   }
>> >>
>> >>    public E poll() {
>> >>       E o = this.obj;
>> >>       if (o == null && !this.done) {
>> >>          return null;
>> >>       }
>> >>       //o will be !null at some point
>> >>       do {
>> >>          if (o != null)
>> >>             return o;
>> >>          java.lang.Thread.onSpinWait();
>> >>          this.obj = o;
>> >>       } while(true);
>> >>    }
>> >>
>> >> Similarly to the queue API: poll should return null iff !done, but
>> offer update first done and then this.obj:
>> >> poll need to read obj, but has to stay consistent to the ordering, so
>> at some point, obj will be visible if done == true.
>> >> On JCtools we have some queues with a similar behaviour (producer
>> sequence is advanced before writing the actual element in the queue)
>> >> and we need to spin wait the element apprearence to stay consistent
>> with the isEmpty behaviour: that's a good use case for onSpinWait (when it
>> works :P).
>> >>
>> >>
>> >>
>> >> Il giorno gio 14 nov 2019 alle ore 16:43 Andrew Haley <aph at redhat.com>
>> ha scritto:
>> >> On 11/14/19 3:31 PM, Francesco Nigro via Concurrency-interest wrote:
>> >> >     E o = this.obj;
>> >> >     if (o == null && !done) {
>> >> >         return null;
>> >> >      }
>> >> >      //o will be !null at some point
>> >> >      do {
>> >> >          if (o != null)
>> >> >             return o;
>> >> >          java.lang.Thread.onSpinWait();
>> >> >      } while(true);
>> >> > }
>> >> >
>> >> > In case like this is more appropriate, maybe, but much less intuitive
>> >> > probably.
>> >>
>> >> Umm, what? o is a local. This loop spins forever.
>> >>
>> >> --
>> >> Andrew Haley  (he/him)
>> >> Java Platform Lead Engineer
>> >> Red Hat UK Ltd. <https://www.redhat.com>
>> >> https://keybase.io/andrewhaley
>> >> EAC8 43EB D3EF DB98 CC77 2FAD A5CD 6035 332F A671
>> >>
>> > _______________________________________________
>> > Concurrency-interest mailing list
>> > Concurrency-interest at cs.oswego.edu
>> > http://cs.oswego.edu/mailman/listinfo/concurrency-interest
>> > _______________________________________________
>> > Concurrency-interest mailing list
>> > Concurrency-interest at cs.oswego.edu
>> > http://cs.oswego.edu/mailman/listinfo/concurrency-interest
>>
>> _______________________________________________
> Concurrency-interest mailing list
> Concurrency-interest at cs.oswego.edu
> http://cs.oswego.edu/mailman/listinfo/concurrency-interest
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://cs.oswego.edu/pipermail/concurrency-interest/attachments/20191115/2a6a9bf9/attachment.html>


More information about the Concurrency-interest mailing list