/ Java  

Java Multithreading 6: Join

This blog will introduce the join() method in Thread. The content includes:

  1. Introduction to join()
  2. join() source code analysis (based on JDK11.0.5)
  3. Example

Introduction to join()

join() is defined in Thread.java.

join() will let the main thread wait for the end of the sub-thread to continue running. Look at the examples:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Main thread
public class Father extends Thread {
public void run() {
Son s = new Son();
s.start();
s.join();
...
}
}
// sub thread
public class Son extends Thread {
public void run() {
...
}
}

Son thread is created and started in Father thread, so Father thread is the main thread and Son thread is the sub-thread.

The Father thread create a new sub-threads through new Son(), and then start sub thread s.start() and call s.join(). After calling s.join(), the Father thread will wait until the sub thread has finished running. After the sub thread s has finished running, the Father thread can continue to run. This is what we mean by join(), so that the main thread will wait for the child thread to finish before continuing to run!

join() source code analysis (based on JDK11.0.5)

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
public final void join() throws InterruptedException {
join(0);
}

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

From the code, we can find out that when millis == 0, it will enter while(isAlive ()) loop. That is, as long as the child thread is alive, the main thread will keep waiting.

Let look back at the above example:

Although s.join() is called in the Father thread, s.join() is the method call on the sub thread s. Then, isAlive() in the join() method should determine whether the sub thread s is in the Alive state. The corresponding wait(0) should also let the sub thread s wait. But if this is the case, how could s.join() make main thread wait until the sub thread s is completed? It should instead make the sub thread s wait (because the wait method of the subb thread s is called)?

Well, the answer is that wait() will make the current thread wait, and the current thread here refers to the thread currently running on the CPU. Therefore, although the wait() of the sub thread is called, it is called through the main thread. Therefore, it is the main thread that waits, not the sub thread!

Example

After understanding the function of join(), let’s look at the usage of join() through examples.

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
public class JoinDemo {
public static void main(String[] args) {
try {
ThreadA t1 = new ThreadA("t1");

// start t1
t1.start();
// join t1 to main thread,and main thread will wait for t1 to complete
t1.join();

System.out.printf("%s finish\n", Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
}

static class ThreadA extends Thread {

public ThreadA(String name) {
super(name);
}

public void run() {
System.out.printf("%s start\n", this.getName());

// delay
for (int i = 0; i < 1000000; i++)
;

System.out.printf("%s finish\n", this.getName());
}
}
}

Results:

1
2
3
t1 start
t1 finish
main finish

The execution sequence is shown in the figure:

  1. Create a new thread t1 in the main thread with new ThreadA("t1"). Next, start thread t1 with t1.start() and execute t1.join().
  2. After executing t1.join(), the main thread will enter the blocked state and wait for t1 to finish running. After t1 ends, it will wake up the main thread, and main thread regains the cpu execution right and continues to run.