Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unsafe.park vs Object.wait

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

  1. Which one should be used in general?
  2. Which one has better performance?
  3. Is there any advantage to using Unsafe.park over Object.wait?
like image 569
BrainStorm.exe Avatar asked Oct 23 '14 18:10

BrainStorm.exe


People also ask

What is a parked thread?

So a parked thread is a thread blocked using LockSupport.

What is Timed_waiting parking?

TIMED_WAITING The thread is waiting for another thread to perform an action for up to a specified waiting time.

What is LockSupport Park?

More specifically, LockSupport provides an alternative for some of Thread's deprecated methods: suspend() and resume(). It uses a concept of permit and parking to detect if given thread should block or not.

What is Park method in Java?

When you call a park method on a Thread, it disables the thread for thread scheduling purposes unless the permit is available. You can call unpark method to make available the permit for the given thread, if it was not already available. So, when your Thread is in WAITING mode by LockSupport.


Video Answer


4 Answers

Most efficient wait is LockSupport.park/unpark, which doesn't require nasty (direct) usage of Unsafe, and doesn't pay to resynchronize your thread's local cache of memory.

This point is important; the less work you do, the more efficient. By not synchronizing on anything, you don't pay to have your thread check with 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 updates that happened "before now", which is why you should use Object.wait() and .notify(), as you must synchronize memory state to use them.

LockSupport allows you to safely park a thread for a given time, and so long as no other thread tries to unpark you, it will wait for that long (barring spurious wake ups). If you need to wait for a specific amount of time, you need to recheck the deadline and loop back into park() until that time has actually elapsed.

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

If you do want other threads to wake you up, chances are high that you need memory synchronization, and should not use park (unless carefully orchestrating volatile fields without race conditions is your thing).

Good luck, and happy coding!

like image 54
Ajax Avatar answered Oct 09 '22 20:10

Ajax


You're not supposed to use either of these methods if you're an application programmer.

They are both too low level, easy to screw up and not meant to be used outside libraries.

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

To answer your question. park(...) works directly on the thread. It takes the thread as a parameter and puts it to sleep until unpark is called on the thread, unless unpark has already been called.

It's supposed to be faster than Object.wait(), which operates on the monitor abstraction if you know which thread you need to block/unblock.

Btw unpark is not really that Unsafe if used from inside Java:

public native void unpark(Object thread)

Unblock the given thread blocked on park, or, if it is not blocked, cause the subsequent call to park not to block. Note: this operation is "unsafe" solely because the caller must somehow ensure that the thread has not been destroyed. Nothing special is usually required to ensure this when called from Java (in which there will ordinarily be a live reference to the thread) but this is not nearly-automatically so when calling from native code.

like image 26
Maxaon3000 Avatar answered Oct 09 '22 18:10

Maxaon3000


LockSupport.park/unpark has better performance, but it's too low level API.

Besides, they have some 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 lock and notify the thread1 to resumed, because lockObject.wait(); will release the lock.

    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, it will cause dead lock. because thread1 won't release the lock by using LockSupport.park. therefore, thread1 can't resumed.

So be careful, they have different behaviors besides blocking the thread. And in fact, there are some Class we can use it conveniently to coordinate in multi-thread environment, such as CountDownLatch, Semaphore, ReentrantLock

like image 38
Wang Kenneth Avatar answered Oct 09 '22 20:10

Wang Kenneth


If you're managing concurrency with synchronized blocks, then you would use Object.wait, notify, and notifyAll for signalling. This is the first kind of concurrency control that Java supported, and it was considered to be very easy to use at the time. It certainly was, compared to everything else that was around.

These days, though, there are lots of classes in java.util.concurrent don't require as much specialized knowledge to work with. These are the things that should be used by average programmers these days.

The park* and unpark methods in LockSupport are what you would use if you are writing your own lock-free algorithms and data structures. They are high-performance constructs that don't require locks to work with, and they are very well designed to make this kind of work as easy as it can be... but that is still very difficult and tricky work that is best left to experts.

like image 42
Matt Timmermans Avatar answered Oct 09 '22 20:10

Matt Timmermans