Thread#join()是否让其他线程通过同步块?

时间:2019-03-05 22:17:04

标签: java multithreading synchronization

Object#wait()方法具有一个有趣的属性,它允许其他线程在被阻止的同时进入其同步块。示例(假设线程1首先运行):

线程1:

synchronized(someLock)
{
    wait();
}

线程2:

synchronized(someLock)
{
    notify();
}

线程2能够唤醒线程1的事实意味着,即使某个其他线程位于同一对象上的同步块中,线程2也进入了同步块。对我来说很好,但是我想知道这是否仅发生在Object#wait()或所有使线程“等待”(Thread#sleep, Thread#join)的方法上。就我而言,我关心Thread#join,因为如果行为与Object#wait()相同,则会破坏我的代码:

private void waitForClose()
{
    try
    {
        // if one thread is waiting in join the other will wait on the semaphore
        synchronized(joinLock)
        {
            if(outputThread != null && Thread.currentThread() != outputThread)
                outputThread.join();
            outputThread = null;

            if(inputThread != null && Thread.currentThread() != inputThread)
                inputThread.join();
            inputThread = null;
        }
    }
    catch(InterruptedException ex)
    {
        logger.error("Interrupted Exception while waiting for thread to join in " + name, ex);
    }
}

那么由于加入调用使线程处于等待状态,多个线程是否有可能进入此同步块?

1 个答案:

答案 0 :(得分:2)

首先,waitnotify机制并不是很有趣。这是在Java中协调两个或多个线程的最基本的方法。了解这里发生的事情很重要:

线程1:

synchronized (someLock) {
  System.out.println("Thread 1 going to wait ...");
  someLock.wait();
  System.out.println("Threads 1 got notified.");
}

线程2:

synchronized (someLock) {
  System.out.println("Notifying");
  someLock.notify();
  System.out.println("Exiting block.");
}

wait()调用将放弃该锁,允许另一个线程抓住它。此时,线程1将无法继续进行,即使它得到通知。该文档明确指出:

  

被唤醒的线程要等到当前   线程放弃了对该对象的锁定。

因此,只有在线程2退出synchronized块之后,线程1才会继续执行wait()之后的代码。

Thread.join()是语法糖,是一种辅助方法,在引擎盖下使用相同的waitnotify / notifyAll()方法。实际上,javadoc警告不要在wait对象上使用notifyThread,以免干扰此机制。

  

此实现使用this.wait循环作为条件   这还活着。当线程终止时,this.notifyAll方法是   调用。建议应用程序不要使用等待,通知或   线程实例上的notifyAll。

Thread.sleep()waitnotify无关。它不需要对象的锁,也不需要位于synchronized块中。

您的代码似乎正在joinLock对象上同步,而outputThread.join()将在outputThread对象上同步并等待。它们是无关的。如果outputThreadjoinLock上进行同步,则可能会有死锁的危险。没有outputThread的代码,我不能说。