简简单单聊一下多线程的join()方法

2022-07-26 17:13:36 浏览数 (1)

码农在囧途

不可否认的是,在这个圆滑当道的时代,如果一个人太过于正直,刚正不阿,那么可能会四处碰壁,而那些世故的机会主义往往如鱼得水,我们面对 这样一个社会规则,我觉得我们可以适当收起自己的锐利,做到知圆滑而不圆滑,知世故而不世故,应该保持一颗年轻的心态,而不是随着年龄的增长 而变得油腻,圆滑,世故。

join()使用场景

当一个方法中调用了多个接口时,为了提升效率,我们通常会使用多线程进行异步调用,不过有一些场景我们需要对某几个接口的值进行汇总,然后再去调用其他的接口, 我们在统计一些报表时,往往会进行大量的运算,调用,然而它们之间会存在依赖,所以我们就需要使用相应的机制来保证执行的顺序,实现方式有很多,Java中我们可以 使用join(),闭锁CountDownLatch(),信号量Semaphore()等,今天我们先从基础的join()说起。

比如调用Rpc接口Api1和Api2成功后,我们用这两个接口的返回值进行处理,然后去调用Api5,那么此时我们就需要在调用Api5之前确保Api1和Api2执行完成。

如上图,Api1和Api2执行完成后再轮到Api5执行,那么我们就可以使用join()方法来做。

join()示例

使用join()后,会阻塞使用join的线程,直到任务执行完成后才会返回,如下,主线程启动了线程1和线程2后,使用了join()将两个线程进行阻塞,等待thread1和thread2 执行完任务后才继续往下执行doIt()方法。

代码语言:javascript复制
public class ThreadOfJoinTest {
    public static void main(String[] args) throws InterruptedException {
        Thread thread1 = new Thread(new Runnable() {
            @SneakyThrows
            @Override
            public void run() {
                Thread.sleep(2000);
                System.out.println("线程1执行完毕");
            }
        });
        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("线程2执行完毕");
            }
        });
        thread1.start();
        thread2.start();
        thread1.join();
        thread2.join();
        doIt();
    }

    public static void doIt(){
        System.out.println("线程1和线程2执行完成后才到我执行");
    }
}

输出

线程2执行完毕 线程1执行完毕 线程1和线程2执行完成后才到我执行

从上面的输出可以看出线程使用join()可以阻塞线程,直到任务完成后才会向下执行。

join源码分析

调用join(millis)或join()后,首先会获取当前的时间戳base,如果传递过来的时间参数millis为0并且线程处于存活状态,那么线程将会一直挂起,直到任务完成, 如果millis大于0,就会计算出线程挂起的时间,然后循环判断挂起的时间当挂起的时间<=0,那么代表当前线程任务已经完成,结束挂起,join()里面挂起线程使用的 是Object中的await()方法。

代码语言:javascript复制
public class Thread implements Runnable{
    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");
        }
        //传过来的时间参数如果为0
        if (millis == 0) {
            //如果线程还是存活状态,那么将会一直挂起
            while (isAlive()) {
                wait(0);
            }
        } else {
            while (isAlive()) {
                //delay时延迟时间
                long delay = millis - now;
                //延迟时间小于0,则证明线程结束挂起
                if (delay <= 0) {
                    break;
                }
                //线程挂起
                wait(delay);
                //计算时间间隔
                now = System.currentTimeMillis() - base;
            }
        }
    }
}

今天的分享就到这里,感谢你观看,下期见。

0 人点赞