Unsafe.park vs Object.wait

I have a couple of questions regarding Unsafe.park and Object.wait (and their respective resume methods):

  1. Which one should be used in general?
  2. Which one has the best performance?
  3. Is there any advantage to using Unsafe.park over Object.wait ?
+15
source share
3 answers

You should not use any of these methods if you are an application programmer.

They are both too low level, they are easy to spoil and they are not intended for use outside the libraries.

Why not try using a higher level construct like java.util.concurrent.locks?

Answer your question. Park (...) runs right in the stream. It takes the stream as a parameter and puts it into sleep mode until unpark is called in it, if unpark has not already been called.

It is supposed to be faster than Object.wait (), which works with monitor abstraction if you know which thread to block / unlock.

By the way, unpacking is not so unsafe if you use it from inside Java :

public native void unpark(Object thread)

Unlock the specified stream blocked during parking, or, if it is not blocked, the subsequent call to the parking is not blocked. Note: this operation is “unsafe” solely because the caller must somehow make sure that the thread has not been destroyed. Nothing special is usually required to guarantee this when calling from Java (which will usually have a direct link to the stream), but this does not happen almost automatically, since when called from native code.

+12
source

The most effective expectation is LockSupport.park/unpark , which does not require dirty (direct) use of Unsafe and does not pay for re-synchronizing the local memory cache of your stream.

This moment is important; the less work you do, the more efficient. Without synchronizing anything, you do not pay to check the thread in the main memory for updates from other threads.

In most cases, this is NOT what you want. In most cases, you want your thread to see all the updates that have occurred so far, so you must use Object.wait () and .notify (), since you must synchronize the memory state in order to use them.

LockSupport allows you to safely park a stream for a given time, and until no other stream tries to cancel your parking, it will wait a long time (excluding false awakenings). If you need to wait a certain time, you need to check the deadline again and return to park () until that time has expired.

You can use it to effectively "sleep", without the need for another thread to wake you up through LockSupport.parkNanos or .parkUntil (for millis; both methods just call Unsafe for you).

If you want other threads to wake you up, chances are good that you need memory synchronization and you should not use parking (unless you need to carefully organize variable fields without race conditions).

Good luck and happy coding!

+14
source

LockSupport.park/unpark has better performance, but this is too low level API.

In addition, they have several different operations, maybe you should notice:

  Object lockObject = new Object(); Runnable task1 = () -> { synchronized (lockObject) { System.out.println("thread 1 blocked"); try { lockObject.wait(); System.out.println("thread 1 resumed"); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }; Thread thread1 = new Thread(task1); thread1.start(); Runnable task2 = () -> { System.out.println("thread 2 running "); synchronized (lockObject) { System.out.println("thread 2 get lock"); lockObject.notify(); } }; Thread thread2 = new Thread(task2); thread2.start(); 

In this case, thread2 can get a lock and notify thread1 to resume, because lockObject.wait(); will unlock.

  Object lockObject = new Object(); Runnable task1 = () -> { synchronized (lockObject) { System.out.println("thread 1 blocked"); LockSupport.park(); System.out.println("thread 1 resumed"); } }; Thread thread1 = new Thread(task1); thread1.start(); Runnable task2 = () -> { System.out.println("thread 2 running "); synchronized (lockObject) { System.out.println("thread 2 get lock"); LockSupport.unpark(thread1); } }; Thread thread2 = new Thread(task2); thread2.start(); 

However, if you use LockSupport.park/unpark like this, this will lead to a deadlock. because thread1 will not release the lock with LockSupport.park . hence thread1 cannot be resumed.

So be careful, they have other behavior than blocking the thread. And in fact, there is some class that we can use for convenience of coordination in a multi-threaded environment, such as CountDownLatch, Semaphore, ReentrantLock

0
source

Source: https://habr.com/ru/post/1205386/


All Articles