行业资讯 2025年08月6日
0 收藏 0 点赞 273 浏览 2571 个字
摘要 :

文章目录 为什么需要 join方法? 分析 解决方法 join(long millis)方法 join方法源码 本文主要讲解Java线程join方法相关的内容,我们来一起学习下吧! 为什么需要 join……




  • 为什么需要 join方法?
  • 分析
  • 解决方法
  • join(long millis)方法
  • join方法源码

本文主要讲解Java线程join方法相关的内容,我们来一起学习下吧!

为什么需要 join方法?

我们先来看下下面的代码执行,我们希望主线程能获取到t1线程修改r之后的值,大家思考下,以下代码打印 r 是什么呢?

package com.panziye.thread;

import java.util.concurrent.TimeUnit;

public class ThreadJoin {
    static int r = 0;
    public static void main(String[] args) {
        test1();
    }

    private static void test1() {
        System.out.println(\"test1 开始\");
        Thread t1 = new Thread(() -> {
            System.out.println(\"t1 开始\");
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(\"t1 结束\");
            r = 10;
        });
        // 启动
        t1.start();
        System.out.println(\"结果为:\"+ r);
        System.out.println(\"test1 结束\");
    }
}

运行发现,输出结果如下:

test1 开始
结果为:0
test1 结束
t1 开始
t1 结束

分析

  • 因为主线程和线程 t1 是并行执行的,t1 线程需要 1 秒之后才能算出 r=10
  • 而主线程一开始就要打印 r 的结果,所以只能打印出 r=0

解决方法

  • 用 sleep 行不行?为什么?
  • 用 join,加在 t1.start() 之后即可

首先主线程用sleep等待t1线程执行完,再去打印r值是可以实现r=10的情况,但是你难以预计sleep的时长,也就是无法预估t1执行的时长,因此不推荐,从而可以是join方法来实现,我们只需要在t1.start()方法后调用t1.join()方法即可等待t1运行结束:

private static void test1() throws InterruptedException {
    System.out.println(\"test1 开始\");
    Thread t1 = new Thread(() -> {
        System.out.println(\"t1 开始\");
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(\"t1 结束\");
        r = 10;
    });
    // 启动
    t1.start();
    // 等待t1运行结束
    t1.join();
    System.out.println(\"结果为:\"+ r);
    System.out.println(\"test1 结束\");
}

由于join方法会抛出中断异常,因此方法也声明抛出即可,再运行测试:

test1 开始
t1 开始
t1 结束
结果为:10
test1 结束

从打印的执行顺序我们也可以发现当调用join方法后,会等待t1线程执行完再去继续执行test1的后续代码,这就是join方法的作用。

join(long millis)方法

join有个重载带参数的方法,参数是等待毫秒值,意思就是如果超过设置的毫秒值线程还没有运行完就不再继续等待,直接继续运行下面的代码,我们可以测试下,我们将上面的代码修改如下:

private static void test1() throws InterruptedException {
    System.out.println(\"test1 开始\");
    Thread t1 = new Thread(() -> {
        System.out.println(\"t1 开始\");
        try {
            // 休眠10s
            TimeUnit.SECONDS.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(\"t1 结束\");
        r = 10;
    });
    // 启动
    t1.start();
    // 等待t1运行结束,超过2s没结束就不再等待
    t1.join(2000);
    System.out.println(\"结果为:\"+ r);
    System.out.println(\"test1 结束\");
}

我们让t1线程运行10s,而join只等待2s,我们会发现直接t1没结束就运行下面的方法了:

test1 开始
t1 开始
结果为:0
test1 结束
t1 结束

join方法源码

为了更方便大家理解join方法,其实我们看下join方法源码就会更清楚了:

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

无参的join就是调用的有参的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;
            }
        }
    }

我们看到其实调用join()方法,其实就是走if (millis == 0)部分逻辑,就是while循环遍历判断线程是否还活着,如果活着则继续等待,一旦运行结束,isAlive也变成了false,就结束等待,跳出循环了,从而继续执行主线程后续代码了。

以上就是Java线程join方法详解的全部内容,希望对你有帮助。欢迎持续关注潘子夜个人博客(www.panziye.com),学习愉快哦!

微信扫一扫

支付宝扫一扫

版权: 转载请注明出处:https://www.zuozi.net/9880.html

管理员

相关推荐
2025-08-06

文章目录 一、Reader 接口概述 1.1 什么是 Reader 接口? 1.2 Reader 与 InputStream 的区别 1.3 …

988
2025-08-06

文章目录 一、事件溯源 (一)核心概念 (二)Kafka与Golang的优势 (三)完整代码实现 二、命令…

465
2025-08-06

文章目录 一、证明GC期间执行native函数的线程仍在运行 二、native线程操作Java对象的影响及处理方…

348
2025-08-06

文章目录 一、事务基础概念 二、MyBatis事务管理机制 (一)JDBC原生事务管理(JdbcTransaction)…

456
2025-08-06

文章目录 一、SnowFlake算法核心原理 二、SnowFlake算法工作流程详解 三、SnowFlake算法的Java代码…

517
2025-08-06

文章目录 一、本地Jar包的加载操作 二、本地Class的加载方法 三、远程Jar包的加载方式 你知道Groo…

832
发表评论
暂无评论

还没有评论呢,快来抢沙发~

助力内容变现

将您的收入提升到一个新的水平

点击联系客服

在线时间:08:00-23:00

客服QQ

122325244

客服电话

400-888-8888

客服邮箱

122325244@qq.com

扫描二维码

关注微信客服号