0.Join()

Thread merging means combining threads from several parallel threads into a single Thread. When a Thread must wait for another Thread to complete its execution, the Thread class provides a join method to do this. Note that this method is not static.

Join has three overloaded methods:

Void join(): the current thread waits for the thread to terminate. Void JOIN (long millis): The maximum time that the current thread waits for this thread to terminate is millis milliseconds. If the thread does not complete within millis time, the current thread enters the ready state and waits for the CPU to schedule again. Void JOIN (long millis,int Nanos): the maximum waiting time for the thread to terminate is millis milliseconds + nanos nanoseconds. If the thread does not complete within millis time, the current thread enters the ready state and waits for the CPU to schedule again.

Reference: Ape code: Gnawing and concurrent (two)

1. Use method

Create a new Thread class and override the run() method:

public class MyThread extends Thread {

    @Override
    public void run() {
        System.out.println("Child thread completes execution"); }}Copy the code

Create a test class and test the Join() method:

Public class TestThread {public static void main(String[] args) {// Loop five timesfor(int i = 0; i < 5; i++) { MyThread thread = new MyThread(); // Start the thread thread.start(); Try {// call join() thread.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Main thread completed");
            System.out.println("~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~"); }}}Copy the code

The following output is displayed:

The child thread is done The main thread is done ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ the child thread is done The main thread is done ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ the child thread is done The main thread is done ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ the child thread is done The main thread is done ~~~~~~~~~~~~~~~ The child thread completes. The main thread completes. ~~~~~~~~~~~~~~~Copy the code

Result analysis: the child thread completes before the main thread every time, that is, the child thread will execute before the main thread.

Loop 5 times in code to eliminate randomness of thread execution, if the problem is not explained, you can increase the loop number to test.

2. Principle analysis

Class Thread:

Public final void join() throws InterruptedException {// When calling join(), the join(long) method is actually called join(0); }Copy the code

Join(long) method

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) {// Call the current judgment because the last passed argument was 0while(isAlive()) {// check whether the child thread isAlivewait(0); / / callwait(0) method}}else {
            while (isAlive()) {
                long delay = millis - now;
                if (delay <= 0) {
                    break;
                }
                wait(delay); now = System.currentTimeMillis() - base; }}}Copy the code

IsAlive ();

/**
     * Tests if this thread is alive. A thread is alive ifIt has been started and has not yet died. If a thread is alive, it is already started and not yet dead. * @return  <code>true</code> if this thread is alive;
     *          <code>false</code> otherwise.
     */****
    public final native boolean isAlive();
Copy the code

Note: This method is a local method that checks whether the thread object is alive or not, true if the thread object is not dead if the start() method is called. In the example above, true is judged because the start() method of the child thread is called and the operation is not terminated.

Wait () method

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

Note: This method is a local method. The current thread calling this method needs to release the lock and wait to wake up. In the example above, the main thread calls the join() method of the child thread object, so the main thread needs to release the lock at this point and wait.

wait() andwait(0) difference: viewwait() method source,waitThe () method is only calledwait(0), as follows: public final voidwait() throws InterruptedException {
        wait(0); } as a result,wait() andwaitSame (0).Copy the code

The main thread waits (), the child thread calls run(), and prints “child thread completed”. At this point, the main thread has not yet been awakened to perform the following operations. So, the question is, who? At what time? Wake up the main thread?

Thread class exit(); Thread class exit();

/** * This method is called by the system to give a Thread * a chance to clean up before it actually exits. Give the thread a chance to free up space before it exits completely. */ private voidexit() {
        if(group ! // The Thread group is created at Thread initialization. The child threads created are group.threadterminated (this); // Call threadTerminated() method group = null; } /* Aggressively null out all reference fields: see bug 4006245 */ target = null; /* Speed the release of some of these resources */ threadLocals = null; inheritableThreadLocals = null; inheritedAccessControlContext = null; blocker = null; uncaughtExceptionHandler = null; }Copy the code

With debug, exit() is called after the thread has executed the run() method. The threadTerminated() method of the thread group is called because there are child threads in the thread group. Check the ThreadGroup. ThreadTerminated () method source code:

/** Notifies the group that the thread {@code t} has terminated. * void threadTerminated(Thread t) { synchronized (this) { remove(t); // Remove this thread from the thread groupif(nthreads == 0) {// notifyAll() when the number of threads in the group is 0; // Wake up all pending threads}if(daemon && (nthreads == 0) && (nUnstartedThreads == 0) && (ngroups == 0)) { destroy(); }}}Copy the code

With this method, the child thread is removed from the thread group and other waiting threads are woken up. In the example above, the child thread is destroyed at this point, releasing the occupied resources and waking up the waiting thread. The main thread waiting in the join() method wakes up and acquires the lock, printing “Main thread completed.”

3. Summary

The Join() method causes the calling thread to wait() (in this case, the main thread) until the thread (in this case, the child thread) on which the calling thread object (in this case, the MyThread object) completes execution.

Since thread startup and destruction are actually operated by the operating system, it is deliberately omitted in the description. If in doubt, you can check the native methods written in C++.Copy the code