Thread 的 join() 方法

关于 Thread 的 join 方法

  • 1、join() 方法说明
  • 2、代码演示
    • 2.1 添加 join() 方法后
    • 2.2 添加 join() 方法前
    • 2.3 对比说明
  • 3、源码理解

 
线程模块,计划用一个系列博文整理总结。上一篇博文:  《 线程系列1:创建线程》
 
 

1、join() 方法说明

 

join() 是Thread的实例方法,官方解释为:等待该线程终止。
 
join() 方法的作用就是:将调用join的线程优先执行,当前正在执行的线程阻塞,直到调用join方法的线程执行完毕
 
或者被打断,主要用于线程之间的交互。

 
“Java 7 Concurrency Cookbook” 对 join() 方法的定义:

public final void join()throws InterruptedException: Waits for this thread to die.

        thread.join() 方法阻塞调用此方法的线程(calling thread),直到线程thread完成,此线程再继续;通常用于在
 
main() 主线程内,等待其它线程完成再结束 main() 主线程。

        另外还有一个应用场景:如何实现让线程T1,T2,T3,在T1执行完成后才执行T2,T2执行完成后才执行T3,
 
也就是线程的串行化,通过 Thread 类的 join() 方法就可以实现

 

2、代码演示

 
代码演示,主要是对比,使用 join()方法前后效果对比。
 
创建线程 Thread-a 代码:


/**
 * @title: ThreadA
 * @description: TODO
 * @date 2019/6/6 
 */
public class ThreadA implements Runnable{

    private String threadName;

    private Thread thread;

    // 构造方法中就启用线程
    ThreadA(String threadName) {
        this.threadName = threadName;
        thread = new Thread(this, threadName);
        thread.start();
    }

    @Override
    public void run() {
        System.out.println("线程" + Thread.currentThread().getName() + "业务逻辑开始!");
       for(int i = 6; i > 0 ; i--) {
         // 线程睡眠1秒
         try {
             Thread.sleep(1000);
             System.out.println(Thread.currentThread().getName() + " : " + i);
         }  catch (Exception e) {
             System.out.println(Thread.currentThread().getName() + "线程执行异常!");
             e.printStackTrace();
         }
       }
       System.out.println(Thread.currentThread().getName() + " 线程结束!");
    }

    public String getThreadName() {
        return threadName;
    }

    public Thread getThread() {
        return thread;
    }
}

2.1 添加 join() 方法后

 
测试代码一:


/**
 * @title: ThreadMain
 * @description: TODO
 * @date 2019/6/6 
 */
public class ThreadMain {


    public static void main(String[] args) throws InterruptedException {

       // 创建线程 B
       Thread threadB = new Thread(new Runnable() {
            @Override
            public void run() {
                // 启动线程 Thread-a
                ThreadA threadA = new ThreadA("Thread-a");
                try {
                    // 加入 join 方法
                    threadA.getThread().join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                // 线程B的业务逻辑
                System.out.println("开始线程 " + Thread.currentThread().getName() + "业务逻辑");
                for (int i = 6; i > 0 ; i--) {
                    try {
                        System.out.println(Thread.currentThread().getName() + " : " + i);
                        // 睡眠0.5秒
                        Thread.sleep(500);
                    } catch (Exception e) {
                        System.out.println(Thread.currentThread().getName() + " 线程执行异常!");
                        e.printStackTrace();
                    }
                }

                System.out.println(Thread.currentThread().getName() + " 线程结束!");

            }
       }, "Thread-B");

       // 启动线程B
       threadB.start();
       // 加入 join 方法
       threadB.join();

        // 主线程业务逻辑开始
        System.out.println("主线程业务逻辑开始");
        for (int i = 6; i > 0 ; i--) {
            try {
                System.out.println(Thread.currentThread().getName() + " : " + i);
                // 睡眠0.3秒
                Thread.sleep(300);
            } catch (Exception e) {
                System.out.println(Thread.currentThread().getName() + " 线程执行异常!");
                e.printStackTrace();
            }
        }

        System.out.println(Thread.currentThread().getName() + " 线程结束!");
    }
}

 
运行结果一:
Thread 的 join() 方法_第1张图片
 

2.2 添加 join() 方法前

 
测试代码二,仅将测试代码一中的,两次调用 join() 方法部分注释掉,其他部分均一样。
 
测试代码二:


/**
 * @title: ThreadMain
 * @description: TODO
 * @date 2019/6/6 
 */
public class ThreadMain {


    public static void main(String[] args) throws InterruptedException {

       // 创建线程 B
       Thread threadB = new Thread(new Runnable() {
            @Override
            public void run() {
                // 启动线程 Thread-a
                ThreadA threadA = new ThreadA("Thread-a");
//                try {
//                    // 加入 join 方法
//                    threadA.getThread().join();
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }
                // 线程B的业务逻辑
                System.out.println("开始线程 " + Thread.currentThread().getName() + "业务逻辑");
                for (int i = 6; i > 0 ; i--) {
                    try {
                        System.out.println(Thread.currentThread().getName() + " : " + i);
                        // 睡眠0.5秒
                        Thread.sleep(500);
                    } catch (Exception e) {
                        System.out.println(Thread.currentThread().getName() + " 线程执行异常!");
                        e.printStackTrace();
                    }
                }

                System.out.println(Thread.currentThread().getName() + " 线程结束!");

            }
       }, "Thread-B");

       // 启动线程B
       threadB.start();
       // 加入 join 方法
//       threadB.join();

        // 主线程业务逻辑开始
        System.out.println("主线程业务逻辑开始");
        for (int i = 6; i > 0 ; i--) {
            try {
                System.out.println(Thread.currentThread().getName() + " : " + i);
                // 睡眠0.3秒
                Thread.sleep(300);
            } catch (Exception e) {
                System.out.println(Thread.currentThread().getName() + " 线程执行异常!");
                e.printStackTrace();
            }
        }

        System.out.println(Thread.currentThread().getName() + " 线程结束!");
    }
}

 
运行结果二:
Thread 的 join() 方法_第2张图片
 

2.3 对比说明

 

       测试代码一和测试代码二,唯一的差别就是:测试代码二将测试代码一中的,两次调用 join() 方法部分注释掉了。
 
       代码中,在线程 Thread-B 中调用了线程 Thread-a ,在主线程 Main 中调用了线程 Thread-B。同时,Thread-a
 
线程的睡眠时间是 1 秒,Thread-B 线程的睡眠时间是 0.5 秒,Main 线程的睡眠时间是 0.3 秒。
 
       当加入 join() 方法后:由于Thread-B 线程中调用 Thread-a,优先执行Thread-a 线程,当前正在执行的Thread-B
 
线程堵塞,直到Thread-a 线程执行完毕。同理,由于Main 主线程中调用 Thread-B线程,故优先执行Thread-B 线程,
 
当前正在执行的 Main 主线程堵塞,直到Thread-B 线程执行完毕。

总结:

        join() 方法的作用就是:将调用join的线程优先执行,当前正在执行的线程阻塞,直到调用join方法的线程执行完毕

或者被打断,主要用于线程之间的交互.

 

3、源码理解

 
深入源码了解一下join(),这里仅截取 Thread 类 的 join() 和 join(millis) 方法

package java.lang;

import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.security.AccessController;
import java.security.AccessControlContext;
import java.security.PrivilegedAction;
import java.util.Map;
import java.util.HashMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.locks.LockSupport;
import sun.nio.ch.Interruptible;
import sun.reflect.CallerSensitive;
import sun.reflect.Reflection;
import sun.security.util.SecurityConstants;

public
class Thread implements Runnable {
 
    ……
    ……   /** 这里仅截取 Thread 类 的 join() 和 join(millis) 方法 */
    ……

    /**
     * Waits for this thread to die.
     *
     * 

An invocation of this method behaves in exactly the same * way as the invocation * *

* {@linkplain #join(long) join}{@code (0)} *
* * @throws InterruptedException * if any thread has interrupted the current thread. The * interrupted status of the current thread is * cleared when this exception is thrown. */
public final void join() throws InterruptedException { join(0); } /** * Waits at most {@code millis} milliseconds for this thread to * die. A timeout of {@code 0} means to wait forever. * *

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 * interrupted status 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) { // 无限期等待直到b线程结束 while (isAlive()) { // wait操作,那必然有synchronized与之对应, // 成员方法加了synchronized说明是synchronized(this)。 // 注意这个wait()方法是Object类中的方法 wait(0); } } else { // 等待固定时间,如果b没结束,那么就不等待了。 while (isAlive()) { long delay = millis - now; if (delay <= 0) { break; } wait(delay); now = System.currentTimeMillis() - base; } } }

 
 
 
 
线程模块,计划用一个系列博文整理总结。上一篇博文:  《线程系列1:创建线程》
 
 
 
 
 
 
本文在源码理解部分,参考了博文: 【Java】Thread类中的join()方法原理. 非常感谢博主!!!

你可能感兴趣的:(线程系列,join方法,线程的join(),join()详解,Thread的join方法,join())