Detailed analysis of join() method in JAVA multithreading

Posted by Monadoxin on Sat, 01 Jan 2022 22:18:24 +0100

Although there have been a lot of blogs about thread join() methods, I was confused a few days ago, but I didn't get a detailed explanation, that is, when multiple threads are running in the system, which threads are suspended by join(). Most of the examples given by bloggers look like t.join() method will make all threads pause and wait for the execution of T. Of course, this is also because I do not have a thorough understanding of various methods and synchronization concepts in multithreading. After looking at other people's analysis and their own practice, I finally figured it out and explained it in detail. I hope it can help students who have the same confusion as me.

First, the conclusion is given: the t.join() method will only make the main thread (or the thread calling t.join() enter the waiting pool and wait for the T thread to wake up after execution. It does not affect other threads running at the same time.

The following is the analysis process.

Previously, I only knew about the join() method that it can make t in t.join() execute first, and other threads will be executed only after t is executed. It can turn the parallel execution between threads into serial execution.

package CSDN;
public class TestJoin {
 
	public static void main(String[] args) throws InterruptedException {
		// TODO Auto-generated method stub
		ThreadTest t1=new ThreadTest("A");
		ThreadTest t2=new ThreadTest("B");
		t1.start();
		t2.start();
	}
 
 
}
class ThreadTest extends Thread {
	private String name;
	public ThreadTest(String name){
		this.name=name;
	}
	public void run(){
		for(int i=1;i<=5;i++){
				System.out.println(name+"-"+i);
		}		
	}
}

Operation results:

A-1
B-1
B-2
B-3
A-2
B-4
A-3
B-5
A-4
A-5

It can be seen that thread A and thread B execute alternately.

After adding the join() method (the definition of ThreadTest class is omitted in the following code)

package CSDN;
public class TestJoin {
 
	public static void main(String[] args) throws InterruptedException {
		// TODO Auto-generated method stub
		ThreadTest t1=new ThreadTest("A");
		ThreadTest t2=new ThreadTest("B");
		t1.start();
		t1.join();
		t2.start();
	}
}

Operation results:

A-1
A-2
A-3
A-4
A-5
B-1
B-2
B-3
B-4
B-5

Obviously, use T1 After join(), thread B needs to wait for thread A to execute. Note that T1 Join() needs to wait T1 The execution will have effect only after start() is executed. In addition, if T1 Join() in T2 After start (), it will still be executed alternately, but it doesn't have no effect. This has bothered me for A long time, and I haven't seen it in other blogs.

For further understanding, let's take a look at the source code of join().

    /**
     * Waits for this thread to die.
     *
     * <p> An invocation of this method behaves in exactly the same
     * way as the invocation
     *
     * <blockquote>
     * {@linkplain #join(long) join}{@code (0)}
     * </blockquote>
     *
     * @throws  InterruptedException
     *          if any thread has interrupted the current thread. The
     *          <i>interrupted status</i> of the current thread is
     *          cleared when this exception is thrown.
     */
    public final void join() throws InterruptedException {
        join(0);            //join() is equivalent to join(0)
    }
    /**
     * Waits at most {@code millis} milliseconds for this thread to
     * die. A timeout of {@code 0} means to wait forever.
     *
     * <p> This implementation uses a loop of {@code this.wait} calls
     * conditioned on {@code this.isAlive}. As a thread terminates the
     * {@code this.notifyAll} method is invoked. It is recommended that
     * applications not use {@code wait}, {@code notify}, or
     * {@code notifyAll} on {@code Thread} instances.
     *
     * @param  millis
     *         the time to wait in milliseconds
     *
     * @throws  IllegalArgumentException
     *          if the value of {@code millis} is negative
     *
     * @throws  InterruptedException
     *          if any thread has interrupted the current thread. The
     *          <i>interrupted status</i> of the current thread is
     *          cleared when this exception is thrown.
     */
    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);           //join(0) is equivalent to wait(0), that is, wait for unlimited time until it is notified
            }
        } else {
            while (isAlive()) {
                long delay = millis - now;
                if (delay <= 0) {
                    break;
                }
                wait(delay);
                now = System.currentTimeMillis() - base;
            }
        }
    }

It can be seen that the bottom layer of the join() method is implemented using the wait() method. It can be seen that the join method is A synchronous method when the main thread calls t1 When using the join() method, the main thread first obtains the lock of the t1 object, then enters the method, and calls the wait() method of the t1 object, so that the main thread enters the waiting pool of the t1 object. At this time, thread A is still executing, and the subsequent T2 Start () has not yet been executed, so the B thread has not yet started. After the execution of thread A, the main thread continues to execute and reaches T2 Start(), B thread will start execution.

In addition, we can use the following example to analyze the relationship between the position and function of join()

package CSDN;
 
public class TestJoin {
 
	public static void main(String[] args) throws InterruptedException {
		// TODO Auto-generated method stub
		System.out.println(Thread.currentThread().getName()+" start");
		ThreadTest t1=new ThreadTest("A");
		ThreadTest t2=new ThreadTest("B");
		ThreadTest t3=new ThreadTest("C");
		System.out.println("t1start");
		t1.start();
		System.out.println("t2start");
		t2.start();
		System.out.println("t3start");
		t3.start();
		System.out.println(Thread.currentThread().getName()+" end");
	}
 
}

The operation result is:

main start
t1start
t1end
t2start
t2end
t3start
t3end
A-1
A-2
main end
C-1
C-2
C-3
C-4
C-5
A-3
B-1
B-2
B-3
B-4
B-5
A-4
A-5

A. B, C and main threads run alternately. After adding the join() method

package CSDN;
 
public class TestJoin {
 
	public static void main(String[] args) throws InterruptedException {
		// TODO Auto-generated method stub
		System.out.println(Thread.currentThread().getName()+" start");
		ThreadTest t1=new ThreadTest("A");
		ThreadTest t2=new ThreadTest("B");
		ThreadTest t3=new ThreadTest("C");
		System.out.println("t1start");
		t1.start();
		System.out.println("t1end");
		System.out.println("t2start");
		t2.start();
		System.out.println("t2end");
		t1.join();
		System.out.println("t3start");
		t3.start();
		System.out.println("t3end");
		System.out.println(Thread.currentThread().getName()+" end");
	}
 
}

Operation results:

main start
t1start
t1end
t2start
t2end
A-1
B-1
A-2
A-3
A-4
A-5
B-2
t3start
t3end
B-3
main end
B-4
B-5
C-1
C-2
C-3
C-4
C-5

It can be seen from many experiments that the main thread is in t1 Stop at the join () method and wait for thread A to finish executing before executing t3 Start(), however, does not affect the execution of the B thread. Therefore, it can be concluded that the t.join() method will only make the main thread enter the waiting pool and wait for the t thread to wake up after execution. It does not affect other threads running at the same time.

PS: in the source code of the join, only the wait method is called, and notify is not called at the end. This is because the thread will automatically call its notifyAll method at the time of die to release all resources and locks.

--------
Copyright notice: This is the original article of CSDN blogger "moonlight MOON", which follows the CC 4.0 BY-SA copyright agreement. Please attach the original source link and this notice for reprint.
Original link: https://blog.csdn.net/u013425438/article/details/80205693

Topics: Multithreading