根据我的理解,内部obj.join()
调用wait()
。这意味着join()
总是释放锁(因为wait()
总是在被调用后释放锁。)
API文档explains:
此实现使用以
this.wait
调用为中心的循环this.isAlive
。当一个线程终止this.notifyAll
方法时 调用。建议应用程序不使用wait
,notify
或notifyAll
个实例Thread
。
人here on SO说 join()
没有释放任何锁,因为API没有明确提及它。但这种逻辑对我来说似乎很奇怪。
以下是join()
代码的主要逻辑:
while (isAlive()) {
wait(0);
}
This site进一步增加了混乱(我认为他们错了):
3)
wait()
和join()
方法之间的第三个区别是,当一个线程调用wait()
方法时,它会释放为wait()
上的对象保留的任何锁定被叫,但是调用join()
方法不会释放任何监视器或锁定。
答案 0 :(得分:5)
wait
释放保持在wait
被调用的对象上的监视器,但不释放任何其他监视器。
当前线程必须拥有此对象的监视器。该线程释放该监视器的所有权并等待[...]。
换句话说,给出以下内容:
synchronized (a) {
synchronized (b) {
b.wait();
}
}
在b.wait()
,当前帖子会释放b
的监听器,而不是a
的监听器。
如果在内部使用t.join()
实施t.wait()
,则会在等待时释放t
的监视器,但不会释放任何其他监视器。
顺便提一下,此join
实施是leaky abstraction的情况。如果Thread
使用private final Object monitor;
代替,我们可以说join
没有发布任何监视器,即使它在我们不知情的情况下在内部使用wait
。没有理由记录使用wait
的实现细节,因为我们无法访问监视器,因此我们不需要了解它。
我们知道join
内部使用wait
的原因是最初编写该方法的人选择了我们可以访问的监视器。这就需要揭示实现细节。 join
并不是假设从我们的角度来释放监视器,只是等待一个线程完成,但是选择了一个实现,这需要我们比我们应该知道更多。
答案 1 :(得分:0)
尽管@Radiodef的出色答案阐明并阐明了泄漏抽象的缺点,但以更简单的方式回答@vrinchvucz的困惑,答案是
是的,当线程调用t.join
时,它确实获取并释放了“ a”监视器锁定。该监视器锁定是线程t
本身的监视器锁定,因为在Thread类上实现join方法是通过在this.wait
synchronized
方法内部使用join
来实现的,这是泄漏的@Radiodef指向的抽象问题。
因此,除非线程在调用t
之前获得t.join
本身的监视器锁,我们可以说t.join
调用中不会释放任何客户端/用户获取的监视器锁(因为有问题的监视器锁定与调用t.join
的线程中获得的客户端/用户代码无关。
这是因为Object#wait的文档中已明确说明
请注意,wait方法将当前线程放入 等待此对象的设置,仅解锁该对象;任何其他物体 当前线程可以在其上同步的同时保持锁定 线程在等待。
这就是为什么Thread#join
的文档在保持使用this.wait
使用的实现细节的同时,也没有提及有关释放锁的任何内容。