首页 > 解决方案 > Thread#join() 是否让其他线程通过同步块?

问题描述

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);
    }
}

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

标签: javamultithreadingsynchronization

解决方案


首先,waitandnotify机制并不是那么有趣。它是在 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()是语法糖,一种辅助方法,在底层使用相同的waitand notify/notifyAll()方法。事实上,javadoc警告不要在对象上使用wait和,不要干扰这种机制。notifyThread

此实现使用以 this.isAlive 为条件的 this.wait 调用循环。当线程终止时,将调用 this.notifyAll 方法。建议应用程序不要在 Thread 实例上使用 wait、notify 或 notifyAll。

Thread.sleep()wait与和无关notify。它不需要对象的锁,也不需要在synchronized块中。

您的代码似乎正在同步一个调用的对象joinLock,而outputThread.join()将同步并等待该outputThread对象。他们是无关的。outputThread如果正在同步,您可能会面临死锁的风险joinLock。没有outputThread我不能说的代码。


推荐阅读