【问题标题】:Java Wait/Notify Within Reentrant Synchronized Blocks重入同步块内的 Java 等待/通知
【发布时间】:2015-04-16 14:01:47
【问题描述】:

我对Java synchronized() 块的理解是,如果一个线程已经拥有一个对象上的锁,它可以进入同一个对象上同步的不同块(重入同步)。下面,我认为JVM使用引用计数来增加/减少线程获取锁的次数,并且只有在计数为零时才会释放锁。

所以我的问题是,如果有人遇到这样的一段代码:

synchronized(this)
{
    if (condition == WAITING)
    {
        synchronized(this)
        {
            condition = COMPLETE;

            notify();

            try
            {
                wait();
            }
            catch(InterruptedException  e)
            {
            }
        }
    }
    else
        condition = READY;
}

当调用 wait() 时具体会发生什么?它只是减少计数,还是不考虑计数就释放锁?

在第一种情况下,在我看来,如果发生锁重入,它会产生死锁,因为它仍然拥有锁,因此会在另一个正在等待它的线程上永远等待。

在第二种情况下,我根本看不出第二个同步块的意义是什么。

wait() 的文档说

"当前线程必须拥有此对象的监视器。线程释放此监视器的所有权并等待,直到另一个线程通过调用 notify 方法或 notifyAll 方法通知等待在此对象的监视器上的线程唤醒。线程然后等待直到它可以重新获得监视器的所有权并恢复执行,”

所以我认为第二种情况是正确的,但我可能是错的。那么我是否遗漏了什么,或者我只是遇到了一个可以很容易地从代码中删除的冗余同步块?

【问题讨论】:

  • 如果您看到这样的代码(其中一些无法编译),我建议您删除并重新编写它。注意:第一次调用 notify 时,什么都不会发生,因为没有线程在等待。第二次,由于条件发生变化,您不会调用 notify,因此您的第一个线程将永远等待。
  • 我(糟糕地)编辑了代码以简化它作为示例。条件的东西和不可编译的错误是我,而不是代码/问题本身。此外,条件在其他地方由另一个线程更新。代码的基本 jist 是等待另一个线程完成的线程被通知条件已更改。然后,当它完成时,它会在其他地方调用 notify。
  • 为什么不重写它以使用 Futures 以便知道线程何时完成?
  • a) 因为我将它移植到 C++,而不是维护当前的 Java 代码,并且 b) 即便如此,“完整”对我来说还是用词不当。等待和通知在这里实际上取决于内部状态,而不是任何实际的计算输出。
  • 期货不仅仅用于计算。 C++ 也有未来和承诺。

标签: java wait synchronized reentrancy


【解决方案1】:

if 之后不需要重新获取锁。

wait() 也会完全释放锁(否则很容易死锁)。

我能看到第二个synchronized 的唯一原因是它之前使用了另一个对象,并且有人修改它以使用相同的this

【讨论】:

  • 这也是我的假设。我正在将一个相当大的 Java 代码库移植到 C++,并尝试对其进行重构以避免使用 std::recursive_mutex。感谢您的信息!
  • 只是为了确认这个场景:当线程遇到外部同步块时,它会获取对象上的锁。然后它遇到第二个同步块,这将触发重入。调用了通知,但由于当前线程仍然锁定了对象,因此没有线程可以获取锁。最后调用等待导致当前线程放弃它持有的锁。你同意吗?
  • 没错。这看起来也像是一个构造,可以使用来自 java.util.concurrent 的类更好地处理,但我想代码是旧的,作者可能不熟悉它们。
  • 您的陈述不是:没有什么可以保证在 if 之后重新获取锁。 误导?重入将导致锁计数器增加。换句话说,第二个同步块保证重新获得锁。
  • 固定措辞。英语不是我的母语,所以也许我不应该使用花哨的语言结构 :) 增加锁计数器只在递归情况下才有意义,这样从递归同步上下文返回不会过早放弃锁。但是这里没有这样的东西(因为wait() 不在乎它在同一个对象上同步了多少次)。
猜你喜欢
  • 1970-01-01
  • 2015-01-26
  • 1970-01-01
  • 2017-09-16
  • 2023-03-27
  • 2019-12-23
  • 1970-01-01
  • 2011-04-25
  • 1970-01-01
相关资源
最近更新 更多