[concurrency-interest] Spin Loop Hint support: Draft JEP proposal

Doug Lea dl at cs.oswego.edu
Wed Oct 14 11:04:36 EDT 2015


Some notes after reading follow-ups.

One question is whether there should be a method that clues in
the JVM about what change is being waited for. This is the territory of
monitor-like constructions (see below), as opposed to the
yield/sleep-like constructions that Gil was initially proposing.

For these, the next question is whether this should be more
like Thread.yield() vs Thread.sleep(). If it could be like
sleep, then new a API might not be needed: JVMs could
implement sleep(0, 1) (or any small value of nanosec arg)
using a PAUSE instruction on platforms supporting them.
But sleep is also required to check interrupt status,
which means that at least one extra load would be needed
in addition to PAUSE. So it seems that something yield-like
(with no obligation to check interrupt) is still desirable,
leading either to my original suggestion:

   /**
    * A hint to the platform that the current thread is momentarily
    * unable to progress...
    */
   public static void spinYield();

OR something more analogous to sleep, but without interrupt check:

  /**
   * A hint to the platform that the current thread is unlikely
   * to progress for the indicated duration in nanoseconds...
   */
   public static void yield(long nanoSeconds);

When available, JVMs would implement small values via PAUSE,
larger by calling plain yield(), but in no case promising to
return in either at least or at most the given duration.
While it is a little odd, it seems to cover John Rose's desire
to force an argument dependency.

I think either of these would be OK.

We'd use this functionality in a few places inside java.util.concurrent.
We can't do so as aggressively as some users might like: we
generally bound spin-then-block constructions to an approximation
of best-case unavailability (lock-hold etc) times, so as to
work OK when systems are heavily loaded. When we have done more
than this, we have gotten justifiable complaints. But we also
have "try" and "poll" forms of almost everything so users can
add additional spins themselves. Or create custom sync using
base capabilities.

Back to the question of monitor-like constructions:

Low-level memory-wait instructions are limited in what they
can wait for -- basically only changes at fixed addresses.
This is not an easy fit for GCed languages where the address
of a variable might change. However, there is at least one
case where this can work: park/unpark are (and are nearly forced
to be) implemented using an underlying native-level semaphore.
So it should be possible to at least sometimes use MWAIT
inside park to reduce unproductive context switches.
The "sometimes" part might vary across platforms.
In particular, the implementation of LockSupport.parkNanos
could always just invoke an MWAIT-based intrinsic for small
arguments. It would be great if people working on hotspot
explored such options.

So for this particular application of MWAIT-like support
(which should be vastly more common than other uses anyway),
we could side-step for now analogs of proposed C++ "synchronics"
and the like that would require unknown mechanics on
still-unreleased VarHandles.

-Doug



More information about the Concurrency-interest mailing list