Interviewer: In what order do threads execute in Java?

Summary: Multi-threaded concurrent execution order in Java has always been the focus of interviews. Mastering the execution order of threads in Java will not only make you stand out in interviews, but also enable you to quickly locate "bizarre" problems caused by multi-threaded concurrency problems in your normal work so that you can stand out from your work.

This article is shared from Huawei Cloud Community. In what order do threads execute in Java? You may know wrong! "By Ice River.

Threads in Java may execute in a different order than you think! Decrypt the execution order of multiple threads in a text. When Thread's start() method is called to start a thread, the execution order of the thread is indeterminate. That is, in the same method, the order in which the start() method of a thread is called does not determine the order in which the thread is executed after multiple threads have been created consecutively.

The execution order of threads is indeterminate

When the Thread start() method is called to start a thread, the execution order of the thread is indeterminate. That is, in the same method, the order in which the start () method of a thread is called does not determine the order in which the thread is executed after multiple threads have been created consecutively.

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 is called directly in the order of threads. Start() method execution does not ensure the order in which threads execute
 */
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. Next, thread1 is called in sequence in the program. Start (), thread2.start() and thread3. The start () method starts three different threads.

So, the question arises, does the thread execute in the order thread1, thread2, and thread3? Run the main method of ThreadSort01 as shown below.

thread1
thread2
thread3

When run again, the results are as follows.

thread1
thread3
thread2

At the third run, the results are as follows.

thread2
thread3
thread1

Note: Everyone may be running differently.

You can see that threads may execute in different order each time the program is run. The order in which a thread is started does not determine the order in which it is executed.

How to ensure the execution order of threads

1. A simple example of ensuring the order in which threads execute

In real-world business scenarios, sometimes a later-started thread may need to rely on the first-started thread execution to complete in order to properly execute the business logic in the thread. At this point, you need to ensure the order in which the threads execute. So how do you ensure the order in which threads execute?

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

package io.binghe.concurrent.lab03;
/**
 * @author binghe
 * @version 1.0.0
 * @description Thread. The join() method ensures the order in which threads execute
 */
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();

        //Let the main thread actually wait for the child thread to finish executing
        thread1.join();

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

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

You can see that the ThreadSort02 class is analogous to the ThreadSort01 class, with the join() method calling the thread added under each thread's startup method. At this point, run the ThreadSort02 class, as shown below.

thread1
thread2
thread3

When run again, the results are as follows.

thread1
thread2
thread3

At the third run, the results are as follows.

thread1
thread2
thread3

You can see that the results are the same for each run, so using Thread's join() method ensures that the threads execute in the same order.

2. How the join method ensures the execution order of threads

Now that the Thread class join() method ensures the order in which threads execute, let's see what the Thread class join() method is.

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 one of the same kind of join() method with a parameter of 0. Continue with 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;
		}
	}
}

You can see that a join() method with a long type parameter is decorated with synchroinzed, indicating that the method can only be called by one instance or method at a time. Since the parameter passed is 0, the program enters the following code logic.

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

First, in your code, use a while loop to determine if the current thread has been started and active. If it has already been started, call the wait() method in the same class and pass parameter 0. Continue to follow up the wait () method, as shown below.

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

You can see that the wait() method is a local method that calls the underlying JDK method through JNI to make the thread wait for execution to complete.

It is important to note that when a thread's wait() method is invoked, the main thread will be in a waiting state, waiting for the child thread to finish executing and then executing down again. That is, in the main() method of the ThreadSort02 class, calling the child thread's join() method will block the main() method from executing. When the child thread finishes executing, the main() method will continue executing down, start the second child thread, execute the child thread's business logic, and so on.

summary

Multi-threaded concurrent execution order in Java has always been the focus of interviews. Mastering the execution order of threads in Java will not only make you stand out in interviews, but also enable you to quickly locate "bizarre" problems caused by multi-threaded concurrency problems in your normal work and make you stand out from your work.

 

Click Attention to learn about Huawei Cloud Fresh Technology for the first time~

Keywords: Java JDK Interview

Added by newhen on Mon, 07 Mar 2022 19:59:39 +0200