Java-Thread.join方法

Thread 类的 join 方法

今天看到一个问题

如何确保 main 方法所在的线程是 Java 程序最后结束的线程

答案是使用 join 方法

于是去了解了一下这个方法

join 的作用

引言

跟刚才我看到的问题类似, 一个面试题:

Java 中如何让多线程按照自己指定的顺序执行?

最简单的回答就是通过 Thread.join 来实现

直接上代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public class JoinDemo extends Thread {

int i;
Thread previousThread; //上一个线程

public JoinDemo(Thread previousThread, int i) {
this.previousThread = previousThread;
this.i = i;
}

@Override
public void run() {
try {
//调用上一个线程的join方法
previousThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
Thread.sleep((long) Math.random() * 10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("num:" + i);
}

public static void main(String[] args) {
Thread previousThread = Thread.currentThread();
for (int i = 0; i < 10; i++) {
JoinDemo joinDemo = new JoinDemo(previousThread, i);
joinDemo.start();
previousThread = joinDemo;
}
}
}

代码中,每个线程会随机 sleep 一段时间, 如果将previousThread.join()注释掉,结束顺序将会随机

如果不注释,可以看到结果为 0 到 9 依次排列

所以 join 对于线程的作用就是阻塞,等待线程中止后返回.

注意阻塞这一点,如果线程一直不结束,将会一直阻塞

注意: 必须在 start 之后调用 join 才有意义

join 原理

看一下源码来理解一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public final synchronized void join(long millis)
throws InterruptedException {
long base = System.currentTimeMillis();
long now = 0;

if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}

if (millis == 0) {
while (isAlive()) {
wait(0);
}
} else {
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
wait(delay);
now = System.currentTimeMillis() - base;
}
}
}

可以看到, 核心是调用 wait 方法(Object 类的)

由于 wait 方法必须要获取锁, 所以 join 方法被 synchronized 修饰, 在方法层面, 相当于 synchroinzed(this), 是本身的实例

线程执行完毕唤醒主线程的原因

对于线程来说, wait 方法阻塞之后需要 notify/notifyall 来唤醒.那么这个 join 最后是怎么唤醒主线程的? 是因为底层的源码在线程执行完毕后有一个唤醒操作

join 的使用场景

适用于我们需要等待线程执行结果来进行后续处理的场合

参考资料:

  1. https://zhuanlan.zhihu.com/p/53078651
  2. https://www.cnblogs.com/duanxz/p/5038471.html
  3. https://www.journaldev.com/1024/java-thread-join-example