Java基础填坑日志(2)——Thread.join()方法使用分析

前言

在学习java中的并发的时候,很容易注意到一个函数join,此函数的功能是等待指定的线程死亡或者经过指定的毫秒数,如果不指定毫秒数或者指定的毫秒数为空,则一直等待直到指定的线程死亡。JDK源码如下:

/**
 * 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) { // 会检测线程是否存活,如果线程已经死亡则不需要等待 while (isAlive()) { wait(0); } } else { while (isAlive()) { long delay = millis - now; if (delay <= 0) { break; } wait(delay); now = System.currentTimeMillis() - base; } } }

join()就等价于join(0)join函数的功能挺简单,不过在学习查阅资料的过程中,发现在等待的过程中,会影响到其它线程的工作状态,所以自己写了一个小demo测试了一下,最后总结出了join更深层次的含义。

测试join函数

在下面的小demo中,我写了两个测试的线程,分别开启线程,观察输出。

public class JoinTest {
    public static void main(String[] args) {
        System.out.println("主线程开始执行");

        Runnable r1 = () -> {
            System.out.println("线程1开始执行");
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {

            }
            System.out.println("线程1结束执行");
        };

        Runnable r2 = () -> {
            System.out.println("线程2开始执行");
            try {
                Thread.sleep(5);
            } catch (InterruptedException e) {

            }
            System.out.println("线程2结束执行");
        };

        Thread t1 = new Thread(r1);
        Thread t2 = new Thread(r2);

        t1.start();
        t2.start();
        System.out.println("主线程结束执行");
    }
}
----------输出结果----------
主线程开始执行
主线程结束执行
线程1开始执行
线程2开始执行
线程2结束执行
线程1结束执行
----------分析----------
主线程开始->线程1、线程2随机某个时点开始执行
(可能在主线程结束后,线程12结束时间点由开始时间和运行时长决定)->主线程结束执行

对于上面的demo,可以很明显的看出,在主线程执行的时候,开启了两个新线程,但是两个新线程的开始执行时间是随机的,而结束时间我人为设置了线程2会执行得更快。

public class JoinTest {
    public static void main(String[] args) {
        System.out.println("主线程开始执行");
        ......
        Thread t1 = new Thread(r1);
        Thread t2 = new Thread(r2);

        t1.start();
        try {
            t1.join();
        } catch (InterruptedException e) {

        }
        t2.start();
        System.out.println("主线程结束执行");
    }
}
----------输出结果----------
主线程开始执行
线程1开始执行
线程1结束执行
主线程结束执行
线程2开始执行
线程2结束执行
----------分析----------
主线程开始->线程1随机某个时点开始执行->线程1结束执行->
主线程结束执行->线程2随机某个时点开始执行(可能在主线程结束前)->线程2结束执行

当主线程调用线程1的join()方法,主线程进入等待状态,直到线程1运行结束,主线程才由等待状态转为可执行状态,所以一定是在线程1结束后主线程才能结束执行。

public class JoinTest {
    public static void main(String[] args) {
        System.out.println("主线程开始执行");
        ......
        Thread t1 = new Thread(r1);
        Thread t2 = new Thread(r2);

        t1.start();
        t2.start();
        try {
            t2.join();
        } catch (InterruptedException e) {

        }
        System.out.println("主线程结束执行");
    }
}
----------输出结果----------
主线程开始执行
线程1开始执行
线程2开始执行
线程2结束执行
主线程结束执行
线程1结束执行
----------分析----------
主线程开始->线程1、线程2随机某个时点开始执行
(可能在主线程结束后,线程12结束时间点由开始时间和运行时长决定)->
线程2结束执行->主线程结束执行

同理,当主线程调用线程2的join()方法,主线程进入等待状态,直到线程2运行结束,主线程才由等待状态转为可执行状态,所以一定是在线程2结束后主线程才能结束执行。

总结

A线程中,使用B.join()函数后会等待指定的线程死亡,然后继续运行,如果有其它线程C其执行规则不变。

参考

多线程中join()
Thread源码分析之join方法

你可能感兴趣的:(java,多线程,java,多线程)