关于Thread.join()方法的理解

本文详细解析了Java多线程中join方法的工作原理,包括其如何使一个线程等待另一个线程结束,以及wait和notify等方法的作用。同时介绍了join方法的不同用法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

之前在学习Java多线程的时候,对join方法理解是:在调用B线程的join方法之后,其他线程只有在B线程执行完毕之后才能执行,但是最近看源码并不是这样的,而是调用B.join()的线程会在B线程执行完毕之后才能执行,其他线程会与B线程交替进行。

下面是jdk8中的关于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;
        }
    }
}

下面的理解以在A线程中调用B.join()为例:

注意到这个方法是一个被synchronized加了锁的方法,也就说明这个方法是线程安全的,锁的对象是this,也就是B。其中最核心部分的代码是下面这几行:

if (millis == 0) {
        while (isAlive()) {
            wait(0);
        }

isAlive()方法判断了B线程是否存活,官方文档中的描述alive的状态为:has been started and has not yet died。其中使用while循环而不是if判断的原因是防止被虚假唤醒

wait()方法是实现join()功能的关键,注意到当进入到这个方法的时候对B加的锁被释放掉,然后等待被唤醒,从而达到A线程等待B线程执行完毕才能执行的目的。

整体的流程如下:

  • A线程调用了B.join()
  • 执行B.join(),对B加锁,锁的持有对象是A
  • 执行到wait()时,A释放掉对B的锁,A因为没有了B的锁,然后陷入等待被唤醒的状态
  • B线程执行,当B执行完毕之后,通过notify()或者notify_all()方法唤醒A(如果B线程中没有显式的使用这两个方法,jvm会在B线程终结的时候调用notify_all()方法)
  • A继续执行

join方法还可以传入一个大于0的数字,起到一个A线程让B线程先执行多长时间的一个作用。

<think>我们参考了用户提供的引用内容,并结合问题要求来解答。 用户问题:理解JavaThread.join()方法的作用以及连续调用多个线程的join()方法(如t1.join(); t2.join();)会产生的效果。 引用[1]说明:join方法的作用是阻塞当前线程,直到被调用的线程结束。如果当前线程调用自己的join方法,会导致死锁。 引用[2]说明:join方法有重载版本可以设置超时时间,避免无限期等待。 根据这些引用,我们可以详细解释join方法的作用和连续调用的效果。 回答结构: 1. Thread.join()方法的作用 2. 连续调用多个join方法(如t1.join(); t2.join();)的含义和效果 3. 注意事项(包括死锁和超时机制) 4. 代码示例 注意:用户的问题中提到了连续调用t1.join()和t2.join(),我们需要解释清楚这种调用方式的效果。</think>### Java Thread.join() 方法详解 #### 一、join() 方法的核心作用 `join()` 方法Java 线程同步的关键机制,其核心功能是**阻塞当前线程,直到目标线程执行结束**。具体表现为: 1. **阻塞特性**:当线程 A 调用线程 B 的 `join()` 方法时,线程 A 会进入阻塞状态,直到线程 B 终止[^1] 2. **执行顺序控制**:确保被 join 的线程先于当前线程完成执行 3. **资源同步**:常用于等待子线程完成数据处理后再进行主线程操作 #### 二、连续调用多个 join() 的行为分析 当连续调用多个线程的 join 方法时(如 `t1.join(); t2.join();`),其执行流程如下: ```java Thread t1 = new Thread(/* 任务1 */); Thread t2 = new Thread(/* 任务2 */); t1.start(); t2.start(); // 连续 join 调用 t1.join(); // 主线程阻塞,等待 t1 结束 t2.join(); // 主线程继续阻塞,等待 t2 结束 System.out.println("所有线程执行完毕"); ``` ##### 执行效果: 1. **顺序阻塞** - 主线程首先在 `t1.join()` 处阻塞,等待 t1 终止 - t1 终止后,主线程在 `t2.join()` 处继续阻塞,等待 t2 终止 - 相当于创建了**串行等待链** 2. **执行时间叠加** 总等待时间 = Max(t1执行时间, t2执行时间) *(若 t1 和 t2 并行执行)* 3. **非执行顺序约束** - 不保证 t1 在 t2 之前开始执行(取决于线程调度) - 只保证主线程在 t1 和 t2 都结束后才继续执行 #### 三、典型应用场景 1. **结果聚合** 等待多个工作线程完成数据处理后汇总结果 ```java List<Thread> workers = new ArrayList<>(); // 启动10个工作线程 for(int i=0; i<10; i++) { Thread t = new DataProcessor(); t.start(); workers.add(t); } // 等待所有线程完成 for(Thread t : workers) { t.join(); // 主线程等待每个工作线程结束 } System.out.println("所有数据处理完成"); ``` 2. **任务依赖管理** 确保前置任务完成后才启动后续任务 ```java Thread initTask = new Initializer(); Thread mainTask = new MainProcessor(); initTask.start(); initTask.join(); // 等待初始化完成 mainTask.start(); // 启动主任务 ``` #### 四、注意事项与最佳实践 1. **避免死锁陷阱** 绝对不要在线程内部调用自身 join: ```java public void run() { Thread.currentThread().join(); // 导致死锁![^1] } ``` 2. **使用超时机制** 通过重载方法防止无限期阻塞: ```java t.join(5000); // 最多等待5秒[^2] if(t.isAlive()) { System.out.println("线程执行超时"); } ``` 3. **中断处理** 当线程被中断时抛出 `InterruptedException`: ```java try { t.join(); } catch (InterruptedException e) { // 处理中断逻辑 } ``` 4. **性能优化** 对于多个线程的等待,优先使用 `ExecutorService`: ```java ExecutorService pool = Executors.newFixedThreadPool(5); // 提交任务... pool.shutdown(); pool.awaitTermination(1, TimeUnit.MINUTES); // 更高效的等待 ``` #### 五、连续 join 的时序图 ```mermaid sequenceDiagram participant Main as 主线程 participant T1 as 线程t1 participant T2 as 线程t2 Main->>T1: t1.start() Main->>T2: t2.start() Main->>T1: t1.join() Note over Main,T1: 主线程阻塞 T1-->>Main: t1终止 Main->>T2: t2.join() Note over Main,T2: 主线程再次阻塞 T2-->>Main: t2终止 Main->>Main: 继续执行后续代码 ``` > **关键结论**:连续调用 `t1.join(); t2.join();` 会使主线程依次等待 t1 和 t2 完成,但不会改变 t1 和 t2 本身的并行执行特性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值