Join literally means joining. Let’s take a look at the explanation and implementation of the join method.
/** * Waits for this thread to die. * The caller thread (the thread that calls the join method) performs a waiting operation until the called thread (the thread to which the join method belongs) ends and is woken up again* <p> An invocation of this method behaves in exactly the same * way as the invocation * * * @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); }Here join is called
/** * Waits at most {@code millis} millionseconds for this thread to * die. A timeout of {@code 0} means to wait for the thread execution to end, or the specified maximum waiting time has arrived, the caller's thread is awakened again. If the maximum waiting time is 0, you can only wait for the thread execution to end before you can wake up. * <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. * * */ 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 itself implements waiting through the wait method. It is judged here that if the thread is still running, continue to wait. If the specified time has come, or the thread has completed running, the code continues to execute downwards, and the calling thread can execute the subsequent logic.
But here I don't see where to call the notify or notifyAll method. If it is not called, the caller thread will keep waiting. Where did the method to wake it up? Through verification, it was found that when the thread ended, the java virtual machine executed the thread's local exit method.
//Thread exit function: void JavaThread::exit(bool destroy_vm, ExitType exit_type) {...//This will handle the join-related destruction logic ensure_join(this);...}//Process the join-related destruction logic static void ensure_join(JavaThread* thread) { Handle threadObj(thread, thread->threadObj()); ObjectLocker lock(threadObj, thread); thread->clear_pending_exception(); java_lang_Thread::set_thread_status(threadObj(), java_lang_Thread::TERMINATED); java_lang_Thread::set_thread(threadObj(), NULL); // Here we call the notifyAll method to wake up the waiting thread lock.notify_all(thread); thread->clear_pending_exception(); }This will understand when the thread is awakened. Let’s write an example below to see the effect.
public class JoinTest { public static void main(String[] args) { ThreadBoy boy = new ThreadBoy(); boy.start(); } static class ThreadBoy extends Thread{ @Override public void run() { System.out.println("Boy and girl are ready to go shopping"); ThreadGirl girl = new ThreadGirl(); girl.start(); try { girl.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("The boy and the girl start shopping"); } } static class ThreadGirl extends Thread{ @Override public void run() { int time = 5000; System.out.println("The girl starts to put on makeup, the boy is waiting..."); try { Thread.sleep(time); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("The girl is finished with makeup!, time taken" + time); } } } } The execution result is:
The boy and the girl are going out shopping and the girl starts putting on makeup, the boy is waiting. . .
The girl's makeup is finished! , 5000
The boy and the girl started shopping
The boy and the girl are going to go shopping. The girl needs to put on makeup first. After the girl has finished makeup, she will go shopping together.
So what is the usage of join(time)?
public class JoinTest { public static void main(String[] args) { ThreadBoy boy = new ThreadBoy(); boy.start(); } static class ThreadBoy extends Thread{ @Override public void run() { System.out.println("Boy and girl are ready to go shopping"); ThreadGirl girl = new ThreadGirl(); girl.start(); int time = 2000; try { girl.join(time); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("The boy waited" + time + ", I don't want to wait any longer, I go shopping"); } } static class ThreadGirl extends Thread{ @Override public void run() { int time = 5000; System.out.println("The girl started to put on makeup, the boy was waiting... "); try { Thread.sleep(time); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("The girl finished making up!, time taken" + time); } } } Here, the join method is only replaced with the join (time) method. The description has been changed, and the printing result is:
The boy and the girl are going out shopping and the girl starts putting on makeup, the boy is waiting. . .
The boy waited 2,000, and didn't want to wait any longer. He went shopping and the girl finished putting on makeup! , 5000
The boy waited for the time in join(time). If the thread where the girl was in has not been executed after this time has arrived, he will not wait any longer and continue to execute the subsequent logic, just to go shopping by himself without waiting for the girl.
From this we can see that the join method is to achieve synchronous execution of two threads more conveniently. Thread 1 executes. After encountering thread 2, wait for thread 2 to execute, and then continue to execute thread 1's execution. The meaning of joining is now more visual.
The above is all the content of this article. I hope it will be helpful to everyone's learning and I hope everyone will support Wulin.com more.