可重入同步块内的Java等待/通知

可重入同步块内的Java等待/通知,java,wait,synchronized,reentrancy,Java,Wait,Synchronized,Reentrancy,我对Java同步块的理解是,如果一个线程已经拥有一个对象上的锁,那么它可以在同一个对象上输入一个不同的同步块——重入同步。下面,我相信JVM使用引用计数来增加/减少线程获取锁的次数,并且只有当计数为零时才释放锁 所以我的问题是,如果你遇到这样的代码: synchronized(this) { if (condition == WAITING) { synchronized(this) { condition = COMPLE

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

所以我的问题是,如果你遇到这样的代码:

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

            notify();

            try
            {
                wait();
            }
            catch(InterruptedException  e)
            {
            }
        }
    }
    else
        condition = READY;
}
调用wait时具体会发生什么?它是仅仅减少计数,还是不管计数多少都释放锁

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

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

等待的文件说

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


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

没有什么需要在if之后重新获取锁的

等待还将完全释放锁,否则很容易出现死锁


我能看到的第二次同步的唯一原因是,它以前使用了另一个对象,有人错误地将其修改为使用相同的对象。

没有必要在if之后重新获取锁

等待还将完全释放锁,否则很容易出现死锁


我能看到的第二次同步的唯一原因是,它以前使用了另一个对象,有人错误地修改了它以使用相同的对象。

如果您看到这样的代码,其中一些代码无法编译,我建议您删除并重新编写。注意:第一次调用notify时,不会发生任何事情,因为没有线程等待。第二次,由于条件已更改,您不会调用notify,因此您的第一个线程将永远等待。条件和不可编译的错误是我,而不是代码/问题本身。另外,条件在其他地方由另一个线程更新。代码的基本jist是让等待另一个线程完成的线程得到条件已更改的通知。然后,当它完成时,它会调用其他地方的通知。为什么不重写这个来使用一个期货,这样你就知道什么时候线程已经完成了?因为我把它移植到C++,而不维护当前的java代码,而B即使如此,“完整”也是我的一个误称。等待和通知实际上取决于内部状态,而不是任何实际的计算输出。未来不仅仅是计算。而且C++有期货和承诺。如果你看到这样的代码,有些代码不编译,我建议你删除和重写。注意:第一次调用notify时,不会发生任何事情,因为没有线程等待。第二次,由于条件已更改,您不会调用notify,因此您的第一个线程将永远等待。条件和不可编译的错误是我,而不是代码/问题本身。另外,条件在其他地方由另一个线程更新。代码的基本jist是让等待另一个线程完成的线程得到条件已更改的通知。然后,当它完成时,它会调用其他地方的通知。为什么不重写这个来使用一个期货,这样你就知道什么时候线程已经完成了?因为我把它移植到C++,而不维护当前的java代码,而B即使如此,“完整”也是我的一个误称。等待和通知实际上取决于内部状态,而不是任何实际的计算输出。未来不仅仅是计算。C++还有期货和承诺,这也是我的假设。我将一个相当大的java代码基础移植到C++,并试图重构它,以避免使用STD::谢谢你的信息!只是为了确认这种情况:当线程遇到外部同步块时,它将获得对象上的锁。然后它遇到第二个同步块,该块将触发重入。调用Notify,但由于当前线程仍锁定了对象,因此没有线程可以获取锁。最后调用wait,这将导致当前线程放弃其持有的锁。D
你同意吗?完全同意。这看起来也像是一个可以用java.util.concurrent中的类更好地处理的构造,但我认为代码很旧,作者可能不熟悉它们。这不是你的陈述:没有任何东西可以保证在if之后重新获取锁。误导重入将导致锁计数器递增。换句话说,第二个同步块将保证重新获得锁。固定措辞。英语不是我的母语,所以也许我不应该使用花哨的语言结构:增加锁计数器只有在递归情况下才有意义,这样从递归同步上下文返回时不会过早放弃锁。但是这里没有这样的东西,因为wait并不关心它在同一个对象上同步了多少次。这也是我的假设。我将一个相当大的java代码基础移植到C++,并试图重构它,以避免使用STD::谢谢你的信息!只是为了确认这种情况:当线程遇到外部同步块时,它将获得对象上的锁。然后它遇到第二个同步块,该块将触发重入。调用Notify,但由于当前线程仍锁定了对象,因此没有线程可以获取锁。最后调用wait,这将导致当前线程放弃其持有的锁。你同意吗?完全同意。这看起来也像是一个可以用java.util.concurrent中的类更好地处理的构造,但我认为代码很旧,作者可能不熟悉它们。这不是你的陈述:没有任何东西可以保证在if之后重新获取锁。误导重入将导致锁计数器递增。换句话说,第二个同步块将保证重新获得锁。固定措辞。英语不是我的母语,所以也许我不应该使用花哨的语言结构:增加锁计数器只有在递归情况下才有意义,这样从递归同步上下文返回时不会过早放弃锁。但是这里没有这样的东西,因为wait不关心它在同一个对象上同步了多少次。