JUC concurrent programming - Join method analysis: Why does calling the Join method of the sub-thread in the main thread cause the main thread to block instead of the sub-thread? (I haven’t finished writing, I don’t want to write anymore)

1. Example code
public class JoinTest {
    
    public static void main(String[] args) throws Exception {
        String start = nowTime();
        System.out.println(start + "-->" + Thread.currentThread().getName() + " end!");
        
        Thread threadA = new Thread(new JoinThread(2), "A");
        Thread threadB = new Thread(new JoinThread(5), "B");
        Thread threadC = new Thread(new JoinThread(5), "C");
        
        threadA.start();
        threadB.start();
        threadC.start();
        
        threadA.join();
        
        String end = nowTime();
        System.out.println(end + "-->" + Thread.currentThread().getName() + " end!");
    }
    
    static class JoinThread implements Runnable {
        
        private int sleepTime;
        
        public JoinThread(int sleepTime) {
            this.sleepTime = sleepTime;
        }
        
        @Override
        public void run() {
            try {
                String start = nowTime();
                System.out.println(start + "-->" + Thread.currentThread().getName() + " run!");
                Thread.sleep(sleepTime * 1000L);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            String end = nowTime();
            System.out.println(end + "-->" + Thread.currentThread().getName() + " end!");
        }
        
    }
    
    public static String nowTime()
    {
        return LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
    }
}
2. Code description

The code given above is very simple, just a static internal class "JoinThread" that implements the "Runnable" interface and a test class "JoinTest" (used to create multiple threads and execute the join method).

Receive a "sleepTime" parameter in the "JoinThread" method to specify the sleep time, and print the start and end times in the run() method of the thread instance of "JoinThread".

Moreover, we created and specified the sleep time of thread A as 2S, and the sleep time of thread B and thread C as 5S (this can prove that the join method will not affect other running threads. By the way, it will not be mentioned in the article. To analyze, you can find other articles to read)

3. Code running results

It can be seen that after the main thread (main) is started, three sub-threads A, B, and C will be created and started. At the same time, the join method of sub-thread A is called, causing the main thread to block until sub-thread A ends its sleep and wakes up 2 seconds later. The main thread (the action of sub-thread A to wake up the main thread is performed in the Native method, which will be analyzed later), the main thread prints "main end" to end the operation, and then 3 seconds later, sub-thread B and sub-thread C end sleep, and the program ends .

4. Source code analysis and breakpoint debugging
(1) Calling ThreadA.join() will first enter the Thread.join() method, because the join method can specify the waiting time of the main thread. Directly calling the join() method will call the join(0) method, that is, the default is "always" Wait until child thread A ends"

(2) In the join() method, there are three situations. When millis [that is, the waiting time we specify in the join(long millis) method] is less than 0, an exception will be thrown; and when millis is 0, a while loop is used Determine whether the sub-thread is currently in the "active" state, and then use wait(0) to put the main thread in the "waiting" state. The main thread will not continue to print "main end!" on the console until sub-thread A wakes up after the end of sub-thread A; The case where millis is not 0 will not be analyzed in this article (in fact, as long as you read this article, you will naturally understand it. If you copy my code and debug it yourself, you will have a deeper understanding. Literally taking the knowledge away).

(3) wait(0) method analysis

After reading the second step above, you may have a question: Why does the wait(0) method of sub-thread A put the main thread in the "waiting" state instead of leaving sub-thread A in the "waiting" state? ? ? This wait(0) method is obviously for sub-thread A?

Here we have to mention the function of the wait(0) method: let the thread we are currently in enter the "waiting" state.

Someone here must be confused (me too), isn't the current thread sub-thread A? But in fact, we are still in the main thread now. We can understand it as: we just called a common object during the running of the main thread : the join() method of threadA. We have not left the current main thread. You can view it from the following debug see

Thread.currentThread() is the thread we are currently running. We can see that Thread.currentThread()="Thread[main, 5, main]", that is, the thread we are currently in is the main thread !

this refers to which object we are currently in. We called the join() method of threadA in the main thread , so there is no doubt that our current object is: threadA

The isAlive() method of the while loop in the following code

public final synchronized void join(long millis) throws InterruptedException {
  
  

                // Omit some irrelevant code

        while (isAlive()) {
            wait(0);
        }

                // Omit some irrelevant code

}

Just to determine whether the sub-thread is running, isAlive()/this.isAlive() all indicate that sub-thread A: threadA is running, so enter the while loop and call the wait(0) method to pause the main thread!

(4) Sub-thread A ends and the main thread continues to run

As can be seen from the above two pictures, the status of sub-thread A: threadA isAlive()/this.isAlive() is false, indicating that sub-thread A has ended, so the status of the main thread is true.

Execution continues under breakpoint debugging, and the main thread also prints "main end"

Notice! ! ! Because I am writing the article while debugging breakpoints, the "A/B/C end" printing in the above picture will be weird. Please refer to the previous running results for the results, don't get confused! ! !

Finally, after our analysis, we explained in detail why calling the join() method of the sub-thread by the main thread causes the main thread to block instead of blocking the sub-thread.

おすすめ

転載: blog.csdn.net/qq_42924347/article/details/132869632