LockSupport_park和Object_wait的使用方式

Can LockSupport.park() replace Object.wait()?

转载来源: https://stackoverflow.com/questions/39415636/can-locksupport-park-replace-object-wait

ASK:

Currently I’m learning concurrency programming in Java. I notice LockSupport.park() introduced in Java 1.6 is much easier than Object.wait() to use, a typical usage of Object.wait() is like 目前,我正在学习 Java 中的并发编程。我注意到 Java 1.6 中引入的 LockSupport.park()Object.wait() 更容易使用, Object.wait() 的典型用法如下

// Thread1
synchronized (lock) {
    while (condition != true) {
        lock.wait()
    }

    // do stuff
}

// Thread2
synchronized (lock) {
    condition = true;
    lock.notify();
}

And I think I can rewrite it using LockSupport.park() like

// Thread1
while (condition != true) {
    LockSupport.park();
}

// do stuff

// Thread2
condition = true;
LockSupport.unpark(Thread1);

By using LockSupport.park(), tedious synchroinzed block disappears. 通过使用 LockSupport.park() ,繁琐的 synchroinzed 块就消失了。

My question is, should I always prefer LockSupport.park() than Object.wait()? Is there any aspect that Object.wait() does better than LockSupport.park() such as performance?

ANS1:

These two things, wait and park, seem alike but they’re pretty different. 等待和公园这两件事看似相似,实则大相径庭。

Calls to wait happen in the context of locking with synchronized. You have some condition the thread is testing, where you’re testing the state of the object you’re synchronizing on, to decide if the thread can proceed. 对 wait 的调用发生在与 synchronized 锁定的情况下。线程正在测试一些条件,其中包括测试同步对象的状态,以决定线程是否可以继续。 The wait/notify process uses the lock as a middleman for sending notifications where the OS scheduler is in charge of who gets notified. 等待/通知进程使用锁作为发送通知的中间人,由操作系统调度程序负责通知谁。 So the use case here is that you have some component with state you want to protect from concurrent access and if a thread can’t make progress, you want it to wait until it can. 因此,这里的用例是,你有一些组件的状态需要防止并发访问,如果一个线程无法取得进展,你希望它等待,直到可以取得进展为止。

A core part of this is that you are not playing puppet master with the waiting threads, your code doesn’t care who gets notified next, that gets delegated to the scheduler. 这样做的核心是,你不会在等待线程中扮演傀儡主人的角色,你的代码并不关心谁会在下一个被通知,而是将这一任务委托给调度程序。

For park, things are different, there is no locking like what you have with wait, and it is much more of a hands-on puppet master situation. Your code is telling individual threads to go dormant or wake up. 对于 park 来说,情况就不同了,它不存在像 wait 那样的锁定功能,而且更像是一个亲力亲为的傀儡主人。你的代码会告诉各个线程休眠或唤醒。

There is a warning in the API documentation for LockSupport:

These methods are designed to be used as tools for creating higher-level synchronization utilities, and are not in themselves useful for most concurrency control applications. The park method is designed for use only in constructions of the form:

 while (!canProceed()) { ... LockSupport.park(this); }

where neither canProceed nor any other actions prior to the call to park entail locking or blocking. Because only one permit is associated with each thread, any intermediary uses of park could interfere with its intended effects. 在调用 park 之前,canProceed 或任何其他操作都不会导致锁定或阻塞。由于每个线程只关联一个许可证,因此任何中间使用 park 的行为都可能干扰其预期效果。

Your specific example depends on having a lock around the test for the condition, which is what the documentation is telling you not to do with park. Also you need the lock around the “do stuff” part after the wait.

If you are needing something more powerful than synchronized then you might look at ReentrantLock or at different nonblocking approaches but park/unpark is more of a low-level helper than something ready to use in your application. 如果需要比 synchronized 更强大的功能,可以考虑 ReentrantLock 或其他非阻塞方法,但 park/unpark 更像是一个低级辅助工具,而不是可以在应用程序中使用的东西。

Note in your second example your condition needs to be volatile or Atomic or otherwise something where its updates are visible across threads.

请注意,在你的第二个示例中,你的条件需要是易失性的或原子的,或者其更新在线程间可见的。

ANS2

No, Locksupport.park()/unpark() can’t replace Object.wait(). 不行,Locksupport.park()/unpark() 不能替代 Object.wait()。

Locksupport.park()/unpark() doesn’t require you to acquire a lock, but Object.wait() does require you to have synchronized keyword to protect it. Let me tell you why,

while (condition != true) 
  LockSupport.park();

Without synchronized or other protections, some other threads can change the condition variable between these two lines of code. So your code might park/unpark when it really shouldn’t. 如果没有同步或其他保护措施,其他线程可以在这两行代码之间更改条件变量。因此,你的代码可能会在不应该停放的时候停放/取消停放。


评论

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注