Personal Technology Blog (IBLi)

CSDN making the nuggets

The resources

1, Thread. Join method in Java 2, Thread. Join function and principle 3, Thread. Join function and principle

The join method

Join () 2 Join (long millis) // parameter milliseconds 3 Join (long millis,int nanoseconds) // first parameter milliseconds, second parameter nanosecondsCopy the code

Function demonstration

public class JoinDemo implements Runnable{
    public void run() {
        System.err.println("join thread demo ");
    }

    public static void main(String[] args) throws Exception {
        System.err.println("main thread start... ");
        Runnable r = new JoinDemo();
        Thread t = new Thread(r);
        t.setName("ibli joinTest ...");
        t.start();
//        t.join();
        System.err.println("main thread end... ");
    }
}
Copy the code

The above will be t.j oin (); Comment out, one possible result of the execution is as follows:

main thread start... main thread end... Join thread demo could also look like this: main thread start... join thread demo main thread end...Copy the code

But take the comments out, and here’s what happens:

main thread start... 
join thread demo 
main thread end... 
Copy the code

This is a very simple demo and the effect is obvious. When the main thread calls t.jin (), it blocks its current thread and waits until the t thread completes and reaches the end state before the main thread can continue executing.

Let’s look at how join() sets the timeout:

public class JoinDemo implements Runnable{ public void run() { System.err.println("join thread demo "); Try {// the Thread sleeps 4s thread.sleep (4000); } catch (InterruptedException e) { e.printStackTrace(); } List<String> strings = null; System.err.println(strings.get(0)); } public static void main(String[] args) throws Exception { System.err.println("main thread start... "); Runnable r = new JoinDemo(); Thread t = new Thread(r); t.setName("ibli joinTest ..." ); t.start(); // But the timeout of the main join is 1s. System.err.println("main thread end... "); }}Copy the code

Execution effect:

main thread start... 
join thread demo 
main thread end... 
Exception in thread "ibli joinTest ..." java.lang.NullPointerException
	at com.ibli.threadTest.api.JoinDemo.run(JoinDemo.java:14)
	at java.lang.Thread.run(Thread.java:748)
Copy the code

The child thread is set to timeout for 4 seconds, but the main thread wakes up after 1 second without waiting for the child thread to finish executing. Does that meet your expectations? Let’s analyze it according to the source code of JOIN.

Principle of Join method

Here is a schematic of a Join

The join () the source code

The join(0) method is called, which is an overloaded version of join.

public final void join() throws InterruptedException {
        join(0);
}
Copy the code

Here is the core implementation of join:

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; }}}Copy the code

Below is the source code for the isAlive method

public final native boolean isAlive();
Copy the code

This is a local method that determines whether the current thread is active. What is an active state? The active state is when the thread is started and not terminated. A thread is considered alive if it is running or ready to start running.

  • Why does a join block the main thread and not the child thread?

  • The main thread is blocked by previousThread (previousThread). The main thread actually holds the lock on previousThread and then blocks by calling the wait method whose caller is in the main thread. So the main thread is blocked.

  • Call t.in () on the main thread and add new JoinDemo().wait(); It’s the same effect; In this case, the wait method is simply written into the child thread’s method.

  • To reiterate, the join method is used when the main thread blocks, the child thread wakes up the main thread after it finishes executing, and then continues executing the logic after the main thread calls the t.join() method.

At what point does the main thread know to continue? As mentioned above, the main thread is the notifyAll() method called by the child thread of a join after execution to wake up the waiting thread. How do we prove that?

CPP: Thread. CPP: Thread. CPP: Thread. CPP: Thread.

void JavaThread::exit(bool destroy_vm, ExitType exit_type) {
  // Notify waiters on thread object. This has to be done after exit() is called
  // on the thread (if the thread is the last thread in a daemon ThreadGroup the
  // group should have the destroyed bit set before waiters are notified).
  ensure_join(this);
}
Copy the code

The ensure_join method is called

static void ensure_join(JavaThread* thread) { // We do not need to grap the Threads_lock, since we are operating on ourself. Handle threadObj(thread, thread->threadObj()); assert(threadObj.not_null(), "java thread object must exist"); ObjectLocker lock(threadObj, thread); // Ignore pending exception (ThreadDeath), since we are exiting anyway thread->clear_pending_exception(); // Thread is exiting. So set thread_status field in java.lang.Thread class to TERMINATED. java_lang_Thread::set_thread_status(threadObj(), java_lang_Thread::TERMINATED); // Clear the native thread instance - this makes isAlive return false and allows the join() // to complete once we've Done the notify_all below: isAlive() returns false java_lang_Thread::set_thread(threadObj), NULL; // Wake up the waiting thread lock.notify_all(thread); // Ignore pending exception (ThreadDeath), since we are exiting anyway thread->clear_pending_exception(); }Copy the code

In JVM code, the lock.notify_all(thread) method is finally called at the end of thread execution to wake up all waiting threads

Usage scenarios

  • For example, when we use Callable to perform an asynchronous task, we can call join when the main thread processes the return value of the task.
  • There are also scenarios that you want to execute sequentially between threads;

Compare the join() method with sleep()

Let’s talk about the sleep method first:

  • Hibernates the current thread for a specified time.
  • The accuracy of sleep time depends on the system clock and CPU scheduling mechanism.
  • If the sleep method is called in the synchronous context, no other thread can enter the current synchronized block or method without releasing the acquired lock resource.
  • A dormant thread can be woken up by calling the interrupt() method.
  • Sleep is a static method that can be called from anywhere

Compare with the sleep method, which is static and whose thread does not release the lock resource, while the Join method is an object method and releases the object lock during the waiting process.

If join() releases the lock on the object, see if join() releases the lock on the object

Some interview questions about join

A Thread. Join () interview question thinking


It’s too crowded at the bottom we’ll meet you higher.