Abstract: Today, let's take a look at how threads are executed, and what is their order?

This article is shared from the HUAWEI CLOUD community " thread execution order is not the same as you think! ! ", author: Binghe.

1. The execution order of threads is uncertain

When calling the start() method of Thread to start a thread, the execution order of the thread is uncertain. That is to say, in the same method, after multiple threads are created consecutively, the order in which the start() method of the threads is called does not determine the execution order of the threads.

For example, here, look at a simple sample program as shown below.

package io.binghe.concurrent.lab03;

/**
 * @author binghe
 * @version 1.0.0
 * @description 线程的顺序,直接调用Thread.start()方法执行不能确保线程的执行顺序
 */
public class ThreadSort01 {
    public static void main(String[] args){
        Thread thread1 = new Thread(() -> {
            System.out.println("thread1");
        });
        Thread thread2 = new Thread(() -> {
            System.out.println("thread2");
        });
        Thread thread3 = new Thread(() -> {
            System.out.println("thread3");
        });

        thread1.start();
        thread2.start();
        thread3.start();
    }
}

Three different threads are created in the ThreadSort01 class, thread1, thread2, and thread3. Then, in the program, call thread1.start(), thread2.start() and thread3.start() respectively in order to start them. Three different threads.

So, the question is, is the execution order of threads executed in the order of thread1, thread2, and thread3? Run the main method of ThreadSort01, and the result is as follows.

thread1
thread2
thread3

When you run it again, the result is as follows.

thread1
thread3
thread2

On the third run, the results are as follows.

thread2
thread3
thread1

It can be seen that the execution order of threads may be different each time the program is run. The start order of threads does not determine the execution order of threads.

Second, how to ensure the execution order of threads

1. A simple example to ensure the order of thread execution

In actual business scenarios, sometimes, the thread that is started later may need to rely on the completion of the execution of the thread that was started first to correctly execute the business logic in the thread. At this point, you need to ensure the execution order of threads. So how to ensure the execution order of threads?

You can use the join() method in the Thread class to ensure the execution order of threads. For example, the following test code.

package io.binghe.concurrent.lab03;

/**
 * @author binghe
 * @version 1.0.0
 * @description 线程的顺序,Thread.join()方法能够确保线程的执行顺序
 */
public class ThreadSort02 {
    public static void main(String[] args) throws InterruptedException {

        Thread thread1 = new Thread(() -> {
            System.out.println("thread1");
        });
        Thread thread2 = new Thread(() -> {
            System.out.println("thread2");
        });
        Thread thread3 = new Thread(() -> {
            System.out.println("thread3");
        });

        thread1.start();

        //实际上让主线程等待子线程执行完成
        thread1.join();

        thread2.start();
        thread2.join();

        thread3.start();
        thread3.join();
    }
}

As you can see, ThreadSort02 is analogous to the ThreadSort01 class, and the join() method of the calling thread is added below the start method of each thread. At this point, run the ThreadSort02 class, and the results are as follows.

thread1
thread2
thread3

When you run it again, the result is as follows.

thread1
thread2
thread3

On the third run, the results are as follows.

thread1
thread2
thread3

As you can see, the result of each run is the same, so the use of Thread's join() method can ensure the order of execution of threads.

2. How does the join method ensure the execution order of threads

Since the join() method of the Thread class can ensure the execution order of threads, let's take a look at what the hell is the join() method of the Thread class.

Enter the join() method of Thread, as shown below.

public final void join() throws InterruptedException {
    join(0);
}

You can see that the join() method calls a parameterized join() method of its kind and passes the parameter 0. Continue to follow up the code as shown below.

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

As you can see, the join() method with a long type parameter is modified by synchroinzed, indicating that this method can only be called by one instance or method at a time. Since the passed parameter is 0, the program will enter the following code logic.

if (millis == 0) {
    while (isAlive()) {
        wait(0);
    }
}

First, use a while loop in the code to determine whether the current thread has started and is active. If it has started and is active, call the wait() method of the same kind and pass the parameter 0. Continue to follow up on the wait() method, as shown below.

public final native void wait(long timeout) throws InterruptedException;

As you can see, the wait() method is a local method, which calls the JDK low-level method through JNI to make the thread wait for the execution to complete.

It should be noted that when the wait() method of the thread is called, the main thread will be in a waiting state, waiting for the execution of the child thread to finish executing again. That is to say, in the main() method of the ThreadSort02 class, calling the join() method of the child thread will block the execution of the main() method. When the execution of the child thread is completed, the main() method will continue to execute downward and start The second child thread, and execute the business logic of the child thread, and so on.

Click to follow to learn about Huawei Cloud's fresh technology for the first time~


华为云开发者联盟
1.4k 声望1.8k 粉丝

生于云,长于云,让开发者成为决定性力量