Hello everyone, I'm Glacier~~
Recently, readers often ask me: Glacier, in what order are threads executed? In order to answer everyone's question, I will write a separate article today. Well, without further ado, let's get into today's topic.
1. The execution order of threads is indeterminate
When calling the start() method of Thread to start a thread, the execution order of the threads is undefined. That is to say, in the same method, after creating multiple threads consecutively, the order of calling the start() method of the threads does not determine the execution order of the threads.
For example, here, look at a simple example 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. Next, the thread1.start(), thread2.start() and thread3.start() methods are called respectively in the program to start respectively. Three different threads.
So, the question is, is the execution order of threads in the order of thread1, thread2 and thread3? Run the main method of ThreadSort01 and the result is shown below.
thread1
thread2
thread3
When run again, the result looks like this.
thread1
thread3
thread2
On the third run, the results are shown below.
thread2
thread3
thread1
As you can see, the execution order of the threads may be different each time the program is run. The order in which threads are started does not determine the order in which they are executed.
2. How to ensure the execution order of threads
1. Simple example to ensure thread execution order
In actual business scenarios, sometimes, the thread started later may need to rely on the completion of the execution of the thread started first to correctly execute the business logic in the thread. At this point, it is necessary to ensure the execution order of the 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 the threads. For example, the test code below.
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();
}
}
It can be seen that ThreadSot02 is analogous to 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 result is shown below.
thread1
thread2
thread3
When run again, the result looks like this.
thread1
thread2
thread3
On the third run, the results are shown below.
thread1
thread2
thread3
It can be seen that the result of each run is the same, so using the join() method of Thread can guarantee the order of execution of the 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 the threads, let's take a look at what the join() method of the Thread class 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 a parameterized join() method in the same class, and passes the parameter 0. Continue to follow up 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;
}
}
}
It can be seen that the join() method with a long type parameter is modified with synchronized, 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 the while loop in the code to determine whether the current thread has been started and is in an active state. If it has been started and is in an active state, the wait() method in the same class is called, and the parameter 0 is passed. Continue to follow the wait() method as shown below.
public final native void wait(long timeout) throws InterruptedException;
As you can see, the wait() method is a native method that calls the underlying method of the JDK through JNI to make the thread wait for the execution to complete.
should be noted that when calling the wait() method of the thread, the main thread will be in a waiting state, waiting for the child thread to execute downwards again after the execution is completed. 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 child thread is executed, the main() method will continue to execute downwards and start The second child thread executes the business logic of the child thread, and so on.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。