Java监视器的等待集是否优先于条目集?

Pav*_*vel 5 java concurrency multithreading mutex barrier

我想问你一个关于Java多线程的问题。

我有一个监视器,多个线程渴望拥有它。此外,临界区内部this.wait()也会根据某些条件被调用。

AFAIK,监视器有 2 组线程:

  • 入口集 - 刚刚到达的线程聚集并等待轮到它们拥有监视器
  • wait set -this.wait()等待被唤醒的线程

notify但是当/notifyAll被调用时,它们如何竞争呢?等待集中的线程是否比条目集中的线程具有获取监视器的优先级,或者它们是否移动到条目集?

我能否确定下notify一个执行的线程将是等待集中的线程?

Nat*_*hes 3

不。调度程序负责哪个线程接下来获得锁。它可能是收到通知的等待集中的一个。它可能是一个刚刚到达并且还没有进入等待集的线程。假设刚刚收到通知的线程接下来将获得监视器是不安全的。

标准建议是在循环中调用 wait,我们检查正在等待的条件:

synchronized (lock) {
    while (!condition) {
        lock.wait();
    }
    ...
Run Code Online (Sandbox Code Playgroud)

这样,当一个线程退出等待时,它会与任何尚未等待的线程进行相同的检查,以确定是否继续进行。

如果您需要公平性,即希望等待时间最长的线程接下来获取锁,那么您可以尝试 java.util.concurrent.locks 中的显式锁之一,例如ReentrantLock,但请阅读细则:

此类的构造函数接受可选的公平参数。当设置为 true 时,在争用情况下,锁倾向于授予等待时间最长的线程访问权限。否则该锁不保证任何特定的访问顺序。使用由许多线程访问的公平锁的程序可能会显示出比使用默认设置的程序更低的总体吞吐量(即更慢;通常慢得多),但在获取锁的时间上具有较小的差异并保证不会出现饥饿。但请注意,锁的公平性并不能保证线程调度的公平性。因此,使用公平锁的许多线程之一可能会连续多次获得公平锁,而其他活动线程没有进展并且当前没有持有该锁。另请注意,不定时的 tryLock 方法不遵守公平性设置。如果锁可用,即使其他线程正在等待,也会成功。

  • @JimmyB,您似乎误解了这句话“*假设刚刚收到通知的线程接下来将获得监视器是不安全的*”。注意“下一个”这个词。它所说的就是您自己承认的:“*当然,当一个线程等待重新获取时,任意数量的其他线程都可以获取并释放监视器。*”没有人说 `wait()` 可以在不拥有的情况下返回之后的监视器。但由于任意线程都可以获取和释放监视器,因此无法保证在调用“notify()”之前为“true”的“condition”在“wait()”返回时仍然为“true”。因此,循环。 (2认同)