你真正了解Java中的Thread.join()方法吗?

原文链接
https://mp.weixin.qq.com/s/P5bgoNUngVmaR3D9MLbAbg

image

1.概述

在本教程中,我们将讨论Thread类中的不同*join()*方法  。我们将详细介绍这些方法和一些示例代码。

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

您可以快速查看本教程,  以了解有关wait()notify()的更多信息

2. Thread.join()方法

join方法在Thread 类中定义:

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

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

我们可以在以下代码中看到此行为:

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() throws InterruptedException {
Thread t2 = new SampleThread(1);
t2.start();
LOGGER.info("Invoking join");
t2.join();
LOGGER.info("Returned from join");
assertFalse(t2.isAlive());
}

在执行代码时,我们应该期望类似于以下结果:


INFO: Thread Created
INFO: Invoking join
INFO: Thread Thread-1 started
INFO: Thread Thread-1 exiting
INFO: Returned from join

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

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


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

3.  带超时的Thread.join()方法

在*join()方法将保持如果引用的线程被阻塞或时间过长处理等。这可能成为一个问题,因为调用线程将变得无响应。为了处理这些情况,我们使用了join()*方法的重载版本  ,允许我们指定超时期限。

*有两个定时版本重载*join()方法:

public final void join(long millis) throws InterruptedException
最多等待millis的毫秒该线程终止,超时为0意味着永远等待。

public final void join(long millis,int nanos) throws InterruptedException
最多等待 millis 毫秒加上 nanos 纳秒该线程死亡。

我们可以使用如下的超时join()


@Test
public void givenStartedThread_waitsUntilTimedout() throws InterruptedException {

Thread t3 = new SampleThread(10);
t3.start();
t3.join(1000);
assertTrue(t3.isAlive());

}

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

定时*join()*取决于操作系统的计时。因此,我们不能确定 *join()*将完全等待指定的时间。

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

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

“从该线程上的join()成功返回之前,线程中的所有操作都可能发生在任何其他线程。”

这意味着当线程t1调用t2.join()时,t2完成的所有更改在返回时在t1中可见。但是,如果我们不调用  join()  或使用其他同步机制,我们无法保证其他线程中的更改对当前线程可见,即使其他线程已完成。

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

我们可以在下面看到一个不正确同步代码的示例:


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

} while (t4.processingCount > 0);

为了正确同步上面的代码,我们可以 在循环中添加定时的  *t4.join()*或使用其他一些同步机制。

5.结论

*join()*方法对于线程间同步非常有用。在本文中,我们讨论了  *join()方法及其行为。我们还使用join()*方法检查了代码。

image

微信关注:Java知己
每天更新Java知识哦,期待你的到来!

image

猜你喜欢

转载自blog.csdn.net/feilang00/article/details/86735842