Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Thread::yield vs Thread::onSpinWait

Well the title basically says it all, with the small addition that I would really like to know when to use them. And it might be simple enough - I've read the documentation for them both, still can't tell the difference much.

There are answers like this here that basically say:

Yielding also was useful for busy waiting...

I can't agree much with them for the simple reason that ForkJoinPool uses Thread::yield internally and that is a pretty recent addition in the jdk world.

The thing that really bothers me is usages like this in jdk too (StampledLock::tryDecReaderOverflow):

    else if ((LockSupport.nextSecondarySeed() & OVERFLOW_YIELD_RATE) == 0)
        Thread.yield();
    else
        Thread.onSpinWait();
    return 0L;

So it seems there are cases when one would be preferred over the other. And no, I don't have an actual example where I might need this - the only one I actually used was Thread::onSpinWait because 1) I happened to busy wait 2) the name is pretty much self explanatory that I should have used it in the busy spin.

like image 263
Eugene Avatar asked May 09 '19 09:05

Eugene


People also ask

What is thread onSpinWait?

onSpinWait() method has been introduced in Java 9. It is a static method of Thread class and can be optionally called in busy-waiting loops.

What happens when a thread calls yield?

Whenever a thread calls the Thread. yield() method, it gives a hint to the thread scheduler that it is ready to pause its execution.

Why is thread yield discouraged?

Thread is usually used to masquerade synchronization problems and should be avoided. The method Thread. yield() should not be used because its behavior is not consistent across all platforms.

When would you use the yield method of the thread class?

A yield() method is a static method of Thread class and it can stop the currently executing thread and will give a chance to other waiting threads of the same priority. If in case there are no waiting threads or if all the waiting threads have low priority then the same thread will continue its execution.


1 Answers

When blocking a thread, there are a few strategies to choose from: spin, wait() / notify(), or a combination of both. Pure spinning on a variable is a very low latency strategy but it can starve other threads that are contending for CPU time. On the other hand, wait() / notify() will free up the CPU for other threads but can cost thousands of CPU cycles in latency when descheduling/scheduling threads.

So how can we avoid pure spinning as well as the overhead associated with descheduling and scheduling the blocked thread?

Thread.yield() is a hint to the thread scheduler to give up its time slice if another thread with equal or higher priority is ready. This avoids pure spinning but doesn't avoid the overhead of rescheduling the thread.

The latest addition is Thread.onSpinWait() which inserts architecture-specific instructions to hint the processor that a thread is in a spin loop. On x86, this is probably the PAUSE instruction, on aarch64, this is the YIELD instruction.

What's the use of these instructions? In a pure spin loop, the processor will speculatively execute the loop over and over again, filling up the pipeline. When the variable the thread is spinning on finally changes, all that speculative work will be thrown out due to memory order violation. What a waste!

A hint to the processor could prevent the pipeline from speculatively executing the spin loop until prior memory instructions are committed. In the context of SMT (hyperthreading), this is useful as the pipeline will be freed up for other hardware threads.

like image 53
Eric Avatar answered Sep 25 '22 18:09

Eric