The contents involved in this chapter include:
1. Join() introduction
2. Join() source code analysis (based on JDK1.7.0_40)
3. Join() example
1. Join() introduction
join() is defined in Thread.java.
The role of join(): Let the "main thread" wait for the "child thread" to end before continuing to run. This sentence may be a bit obscure, but we should understand it through examples:
The code copy is as follows:
// Main thread
public class Father extends Thread {
public void run() {
Son s = new Son();
s.start();
s.join();
...
}
}
// Child thread
public class Son extends Thread {
public void run() {
...
}
}
illustrate:
The above are two classes Father (main thread class) and Son (subthread class).因为Son是在Father中创建并启动的,所以,Father是主线程类,Son是子线程类。
在Father主线程中,通过new Son()新建“子线程s”。 Then start "child thread s" through s.start() and call s.join(). After calling s.join(), the Father main thread will wait until the "child thread s" is completed; after the "child thread s" is completed, the Father main thread can continue to run. This is what we call "the role of join() is to make the main thread wait for the child thread to end before it can continue to run"!
2. Join() source code analysis (based on JDK1.7.0_40)
The code copy is as follows:
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;
}
}
}
illustrate:
从代码中,我们可以发现。当millis==0时,会进入while(isAlive())循环;即只要子线程是活的,主线程就不停的等待。
We understand the usage of join() based on the above code when explaining the role of join()!
question:
Although the place where s.join() is called occurs in the "Father main thread", s.join() is called join() through "child thread s". Then, isAlive() in the join() method should determine whether the "child thread s" is the Alive state; the corresponding wait(0) should also "let the child thread s" wait. But if this is the case, how could the function of s.join() be "let the main thread wait until the child thread s completes", it should be to let the child thread wait (because the wait method of the child thread object s is called嘛)"?
Answer: The function of wait() is to make the "current thread" wait, and the "current thread" here refers to the thread currently running on the CPU. Therefore, although the wait() method of the child thread is called, it is called through the "main thread"; therefore, the main thread is sleeping, not the "child thread"!
3. join()示例
After understanding the role of join(), let’s check the usage of join() through examples.
The code copy is as follows:
// JoinTest.java source code
public class JoinTest{
public static void main(String[] args){
try {
ThreadA t1 = new ThreadA("t1"); // 新建“线程t1”
t1.start(); // Start "thread t1"
t1.join(); // Add "thread t1" to "main thread main", and "main thread main() will wait for it to complete"
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 operation
for(int i=0; i <1000000; i++)
;
System.out.printf("%s finish/n", this.getName());
}
}
}
Running results:
The code copy is as follows:
t1 start
t1 finish
main finish
Results description:
The operation process is shown in the figure
(01) Create a new "thread t1" in "main thread main" through new ThreadA("t1"). Next, start "thread t1" through t1.start() and execute t1.join().
(02) After executing t1.join(), the "main thread main" will enter the "blocking state" and wait for the end of t1's run. After the "child thread t1" is completed, the "main thread main" will be awakened, and the "main thread" will regain the CPU execution rights and continue to run.