Thread.join()是否释放锁定?或继续持有它?

时间:2018-03-29 15:17:38

标签: java multithreading

根据我的理解,内部obj.join()调用wait()。这意味着join()总是释放锁(因为wait()总是在被调用后释放锁。)

API文档explains

  

此实现使用以this.wait调用为中心的循环   this.isAlive。当一个线程终止this.notifyAll方法时   调用。建议应用程序不使用waitnotify或   notifyAll个实例Thread

here on SO join()没有释放任何锁,因为API没有明确提及它。但这种逻辑对我来说似乎很奇怪。

以下是join()代码的主要逻辑:

 while (isAlive()) {
            wait(0);
        }

This site进一步增加了混乱(我认为他们错了):

  

3)wait()join()方法之间的第三个区别是,当一个线程调用wait()方法时,它会释放为wait()上的对象保留的任何锁定被叫,但是调用join()方法不会释放任何监视器或锁定。

2 个答案:

答案 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使用的实现细节的同时,也没有提及有关释放锁的任何内容。