onSpinWait​() method of Thread class

送分小仙女□ 提交于 2019-12-09 14:01:51

问题


While learning Java 9 I came across a new method of Thread class, called onSpinWait​. According to javadocs, this method is used for this:

Indicates that the caller is momentarily unable to progress, until the occurrence of one or more actions on the part of other activities.

Can someone help me understand this method giving a real-life example?


回答1:


It's the same (and probably compiles to) as the x86 opcode PAUSE and equivalent the Win32 macro YieldProcessor, GCC's __mm_pause() and the C# method Thread.SpinWait

It's a very weakened form of yielding: it tells your CPU that you are in a loop that may burn many CPU-cycles waiting for something to happen (busy-waiting).

This way, The CPU can assign more resources to other threads, without actually loading the OS scheduler and dequeuing a ready-to-run thread (which may be expensive).

a common use for that is spin-locking, when you know the contention on a shared memory is very infrequent or finishes very quickly, a spinlock may preform better than an ordinary lock.

Pseudo code for such can look like:

int state = 0; //1 - locked, 0 - unlocked

routine lock:
    while state.cas(new_value=1, wanted_value=0) == false //if state is 0 (unlocked), store 1 (locked) and return true, otherwise just return false.
       yield

routine unlock:
    atomic_store(state,0)

yield can be implemented wuth Thread.onSpinWait(), hinting that while trying to lock the lock, the CPU can give more resources to other threads.

This technique of yielding is extremely common and popular when implementing a lock-free algorithm, since most of them depend on busy-waiting (which is implemented almost always as an atomic compare-and-swap loop). this has every real-world use you can imagine.




回答2:


Pure system hinting!

Reading this article I quote:

Goals

Define an API that would allow Java code to hint to the run-time system that it is in a spin loop. The API will be a pure hint, and will carry no semantic behaviour requirements (for example, a no-op is a valid implementation). Allow the JVM to benefit from spin loop specific behaviours that may be useful on certain hardware platforms. Provide both a no-op implementation and an intrinsic implementation in the JDK, and demonstrate an execution benefit on at least one major hardware platform.

There are many times a thread must be suspended until something outside its scope changes. A (once) common practice was the wait() notify() pattern where there's one thread waiting for the other thread to wake them up.

There is a big limitation to this, namely, the other thread must be aware that there might be waiting threads and should notify. If the work of the other thread is outside your control, there's no way to get notified.

The only way would be a spin-wait. let's say you have a program that checks for new emails and notifies the user:

while(true) {
    while(!newEmailArrived()) {
    }
    makeNotification();
}

This piece of code will execute millions of times a seconds; spinning over and over, using precious of electricity and CPU power. A common way of doing this would be to wait a few seconds on each iteration.

while(true) {
    while(!newEmailArrived()) {
        try {
            Thread.sleep(5000);
        } catch(InterruptedException e) {
        }
    }
    makeNotification();
}

This does a very good job. But in cases where you have to work instantly a sleep may be out of question.

Java 9 tries to solve this issue by introducing this new method:

while(true) {
    while(!newEmailArrived()) {
        Thread.onSpinWait();
    }
    makeNotification();
}

This will work exactly the same as without the method call, but the system is free to lower the process priority; slowing the cycle or reduce electricity on this loop when its resources are needed for other more important things.




回答3:


I just want to add my 2 cents after reading the document and the source code for it. This method might trigger some optimizations and might not - so care must be taken - you can't really rely on it - since this a hint to the CPU more than demand, probably there's no initial relying whatsoever either way... Meaning that it's actual source code looks like this:

@HotSpotIntrinsicCandidate
public static void onSpinWait() {}

What this actually means is that this method is basically a NO-OP until it hits the c2 compiler in the JIT, according to this




回答4:


For a real-world example, say you wanted to implement asynchronous logging, where threads that want to log something, don't want to wait for their log message to get "published" (say written to a file), just so long as it eventually does (because they've got real work to do.)

Producer(s):
concurrentQueue.push("Log my message")

And say, you decide on having a dedicated consumer thread, that is solely responsible for actually writing log messages to a file:

(Single)Consumer

while (concurrentQueue.isEmpty())
{
    //what should I do?

}
writeToFile(concurrentQueue.popHead());
//loop

The issue is what to do in inside the while block? Java has not provided ideal solutions: you could do a Thread.sleep(), but for how long and that's heavyweight; or a Thread.yield(), but that's unspecified, or you could use a lock or mutex*, but that's often too heavyweight and slows the producers down as well (and vitiates the stated purpose of asynchronous logging).

What you really want is to say to the runtime, "I anticipate that I won't be waiting too long, but I'd like to minimize any overhead in waiting/negative effects on other threads". That's where Thread.onSpinWait() comes in.

As a response above indicated, on platforms that support it (like x86), onSpinWait() gets intrinsified into a PAUSE instruction, which will give you the benefits that you want. So:

(Single)Consumer

while (concurrentQueue.isEmpty())
{
    Thread.onSpinWait();

}
writeToFile(concurrentQueue.popHead());
//loop

It's been shown empirically that this can improve latency of "busy-waiting" style loops.

I also want to clarify, that it is not just useful in implementing "spin-locks" (although it's definitely useful in such a circumstance); the code above does not require a lock (spin or otherwise) of any kind.

If you want to get into the weeds, you can't do better than Intel's specs

*For clarity, the JVM is incredibly smart in attempting to minimize the cost of mutexes, and will use lightweight locks initially, but that's another discussion.



来源:https://stackoverflow.com/questions/44622384/onspinwait-method-of-thread-class

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!