java Unsafe.park 与 Object.wait

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/26534489/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 10:05:52  来源:igfitidea点击:

Unsafe.park vs Object.wait

javamultithreading

提问by BrainStorm.exe

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

我有几个关于Unsafe.parkObject.wait(以及它们相应的简历方法)的问题:

  1. Which one should be used in general?
  2. Which one has better performance?
  3. Is there any advantage to using Unsafe.parkover Object.wait?
  1. 一般应该使用哪一种?
  2. 哪个性能更好?
  3. 使用Unsafe.parkover有什么好处Object.wait吗?

采纳答案by Maxaon3000

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 ?

为什么不尝试使用更高级别的构造,如 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.

回答你的问题。park(...) 直接在线程上工作。它将线程作为参数并将其置于休眠状态,直到在线程上调用 unpark 为止,除非已经调用了 unpark。

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.

它应该比 Object.wait() 更快,如果您知道需要阻塞/解除阻塞的线程,它会在监视器抽象上运行。

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

顺便说一句,如果从 Java 内部使用unpark 并不是那么不安全:

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.

public native void unpark(Object thread)

取消阻塞在 park 上阻塞的给定线程,或者,如果它未被阻塞,则导致后续调用 park 不被阻塞。注意:这个操作是“不安全的”,仅仅是因为调用者必须以某种方式确保线程没有被破坏。当从 Java 调用时,通常不需要任何特殊的东西来确保这一点(其中通常会有对线程的实时引用),但是当从本机代码调用时,这几乎不是自动的。

回答by Ajax

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.

最有效的等待是LockSupport.park/unpark,它不需要讨厌(直接)使用 Unsafe,并且不需要重新同步线程的本地内存缓存。

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.

在大多数情况下,这不是您想要的。在大多数情况下,您希望您的线程看到“之前”发生的所有更新,这就是您应该使用 Object.wait() 和 .notify() 的原因,因为您必须同步内存状态才能使用它们。

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.

LockSupport 允许您在给定的时间内安全地停放线程,只要没有其他线程试图取消停放您,它就会等待那么长时间(除非虚假唤醒)。如果您需要等待特定的时间,则需要重新检查截止日期并循环回到 park() 直到该时间实际过去。

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

您可以使用它来有效地“睡眠”,而无需另一个线程必须通过LockSupport.parkNanosor唤醒您.parkUntil(对于millis;这两种方法都为您调用了 Unsafe )。

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).

如果您确实希望其他线程唤醒您,那么您很可能需要内存同步,并且不应该使用 park(除非您仔细编排没有竞争条件的易失性字段)。

Good luck, and happy coding!

祝你好运,快乐编码!

回答by Wang Kenneth

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

LockSupport.park/unpark具有更好的性能,但它的 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.

在这种情况下,线程 2 可以获得锁并通知线程 1 恢复,因为lockObject.wait();会释放锁。

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

但是,如果这样使用LockSupport.park/unpark,则会导致死锁。因为 thread1 不会通过使用LockSupport.park. 因此,thread1 无法恢复。

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

所以要小心,除了阻塞线程之外,它们还有不同的行为。而且实际上还有一些类我们可以方便的使用它来协调多线程环境,比如CountDownLatch, Semaphore, ReentrantLock

回答by Matt Timmermans

If you're managing concurrency with synchronizedblocks, then you would use Object.wait, notify, and notifyAllfor 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.

如果您管理的并发synchronized块,那么你可以使用Object.waitnotify以及notifyAll用于信令。这是Java支持的第一种并发控制,当时被认为非常好用。与周围的其他一切相比,它确实如此。

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

但是,如今,有很多课程java.util.concurrent不需要太多的专业知识即可使用。这些是现在普通程序员应该使用的东西。

The park*and unparkmethods in LockSupportare 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.

如果您正在编写自己的无锁算法和数据结构,您将使用 中的park*unpark方法LockSupport。它们是不需要锁的高性能结构,它们经过精心设计,使这种工作尽可能简单……但这仍然是非常困难和棘手的工作,最好留下给专家。