The Thread.join() Method in Java – Java中的Thread.join()方法

最后修改: 2018年 6月 4日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

In this tutorial, we’ll discuss the different join() methods in the Thread class. We’ll go into the details of these methods and some example codes.

在本教程中,我们将讨论Thread类中不同的join()方法。我们将深入探讨这些方法的细节和一些示例代码。

Like the wait() and notify() methods, join() is another mechanism of inter-thread synchronization.

wait()notify()方法一样,join()是线程间同步的另一种机制。

You can have a quick look at this tutorial to read more about wait() and notify().

你可以快速浏览一下本教程,以阅读更多关于wait()notify()的信息。

2. The Thread.join() Method

2.Thread.join()方法

The join method is defined in the Thread class:

连接方法定义在线程类中。

public final void join() throws InterruptedException
Waits for this thread to die.

public final void join() throws InterruptedException
等待这个线程死亡。

When we invoke the join() method on a thread, the calling thread goes into a waiting state. It remains in a waiting state until the referenced thread terminates.

当我们在一个线程上调用join()方法时,调用线程会进入等待状态。它一直处于等待状态,直到被引用的线程终止。

We can see this behaviour in the following code:

我们可以在以下代码中看到这种行为。

class SampleThread extends Thread {
    public int processingCount = 0;

    SampleThread(int processingCount) {
        this.processingCount = processingCount;
        LOGGER.info("Thread Created");
    }

    @Override
    public void run() {
        LOGGER.info("Thread " + this.getName() + " started");
        while (processingCount > 0) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                LOGGER.info("Thread " + this.getName() + " interrupted");
            }
            processingCount--;
        }
        LOGGER.info("Thread " + this.getName() + " exiting");
    }
}

@Test
public void givenStartedThread_whenJoinCalled_waitsTillCompletion() 
  throws InterruptedException {
    Thread t2 = new SampleThread(1);
    t2.start();
    LOGGER.info("Invoking join");
    t2.join();
    LOGGER.info("Returned from join");
    assertFalse(t2.isAlive());
}

We should expect results similar to the following when executing the code:

在执行该代码时,我们应该期待与以下类似的结果。

[main] INFO: Thread Thread-1 Created
[main] INFO: Invoking join
[Thread-1] INFO: Thread Thread-1 started
[Thread-1] INFO: Inside Thread Thread-1, processingCount = 0
[Thread-1] INFO: Thread Thread-1 exiting
[main] INFO: Returned from join

The join() method may also return if the referenced thread is interrupted.  In this case, the method throws an InterruptedException.

如果被引用的线程被中断,join()方法也可能返回。 在这种情况下,该方法会抛出一个InterruptedException

Finally, if the referenced thread was already terminated or hasn’t been started, the call to join() method returns immediately.

最后,如果被引用的线程已经被终止或尚未启动,那么对join()方法的调用将立即返回

Thread t1 = new SampleThread(0);
t1.join();  //returns immediately

3. Thread.join() Methods with Timeout

3.Thread.join() 具有超时的方法

The join() method will keep waiting if the referenced thread is blocked or takes too long to process. This can become an issue as the calling thread will become non-responsive. To handle these situations, we use overloaded versions of the join() method that allow us to specify a timeout period.

如果被引用的线程被阻塞或处理时间过长,join()方法将继续等待。这可能会成为一个问题,因为调用线程将变得没有反应。为了处理这些情况,我们使用join()方法的重载版本,允许我们指定一个超时周期。

There are two timed versions that overload the join() method:

有两个计时版本,它们重载了join()方法:

“public final void join(long millis) throws InterruptedException
Waits at most millis milliseconds for this thread to die. A timeout of 0 means to wait forever.”

“public final void join(long millis) throws InterruptedException
最多等待millis毫秒,这个线程就会死亡。超时为0意味着永远等待”

“public final void join(long millis,intnanos) throws InterruptedException
Waits at most millis milliseconds plus nanos nanoseconds for this thread to die.”

“public final void join(long millis,intnanos) throws InterruptedException
最多等待millis毫秒加上nanos纳秒,这个线程就会死亡。”

We can use the timed join() as below:

我们可以使用定时的join(),如下所示。

@Test
public void givenStartedThread_whenTimedJoinCalled_waitsUntilTimedout()
  throws InterruptedException {
    Thread t3 = new SampleThread(10);
    t3.start();
    t3.join(1000);
    assertTrue(t3.isAlive());
}

In this case, the calling thread waits for roughly 1 second for the thread t3 to finish. If the thread t3 does not finish in this time period, the join() method returns control to the calling method.

在这种情况下,调用线程会等待大约1秒的时间来完成线程t3。如果线程t3没有在这段时间内完成,join()方法将控制权返回给调用方法。

Timed join() is dependent on the OS for timing. So, we cannot assume that join() will wait exactly as long as specified.

定时的join()取决于操作系统的定时。因此,我们不能假设join()将完全按照指定的时间来等待。

4. Thread.join() Methods and Synchronization

4.Thread.join()方法和同步化

In addition to waiting until termination, calling the join() method has a synchronization effect. join() creates a happens-before relationship:

除了等到终止之外,调用join()方法还有一个同步的效果。join()创建了一个happens-before>关系:

“All actions in a thread happen-before any other thread successfully returns from a join() on that thread.”

“一个线程中的所有行动都发生在任何其他线程从该线程上的join()成功返回之前。”

This means that when a thread t1 calls t2.join(), all changes done by t2 are visible in t1 on return. However, if we do not invoke join() or use other synchronization mechanisms, we do not have any guarantee that changes in the other thread will be visible to the current thread even if the other thread has been completed.

这意味着,当一个线程t1调用t2.join()时,t2所做的所有改变在返回时在t1中是可见的。然而,如果我们不调用join()或使用其他同步机制,我们就不能保证其他线程的变化对当前线程是可见的,即使其他线程已经完成。

Hence, even though the join() method call to a thread in the terminated state returns immediately, we still need to call it in some situations.

因此,即使对处于终止状态的线程的join()方法调用立即返回,我们仍然需要在某些情况下调用它。

We can see an example of improperly synchronized code below:

我们可以看到下面一个不恰当的同步代码的例子。

SampleThread t4 = new SampleThread(10);
t4.start();
// not guaranteed to stop even if t4 finishes.
do {
       
} while (t4.processingCount > 0);

To properly synchronize the above code, we can add timed t4.join() inside the loop or use another synchronization mechanism.

为了正确地同步上述代码,我们可以在循环内添加定时的t4.join()或者使用其他同步机制。

5. Conclusion

5.总结

join() method is quite useful for inter-thread synchronization. In this article, we discussed the join() methods and their behaviour. We also reviewed the code using the join() method.

join()方法对于线程间的同步相当有用。在这篇文章中,我们讨论了join()方法和它们的行为。我们还回顾了使用join()方法的代码。

As always, the full source code can be found on GitHub.

一如既往,完整的源代码可以在GitHub上找到