5人参与 • 2025-07-26 • Java
join()
方法是 java 并发编程中一个非常重要且基础的方法,它允许一个线程等待另一个线程执行完成。理解它的工作原理和使用场景对于编写健壮的多线程应用程序至关重要。
join()
是 java.lang.thread
类的一个实例方法。它的核心作用是阻塞当前正在执行的线程(我们称之为“主线程”,尽管它可以是任何线程),直到调用 join()
方法的那个线程(我们称之为“目标线程”)执行完毕。
简单来说,如果线程 a 的代码中调用了线程 b 的 join()
方法(即 b.join()
),那么线程 a 就会进入等待状态,直到线程 b 执行结束,线程 a 才会从 b.join()
这行代码继续往下执行。
这就像在一个接力赛中,下一棒的选手(线程 a)必须等待上一棒的选手(线程 b)跑完自己的赛程并交接后,才能开始跑。
thread
类提供了三个版本的 join()
方法:
public final void join()
interruptedexception
,这意味着等待中的线程可能会被中断。public final synchronized void join(long millis)
interruptedexception
。public final synchronized void join(long millis, int nanos)
join(long millis)
类似,只是提供了更高精度的时间控制。你可能会好奇,join()
是如何实现线程等待的?它的底层原理是什么?
isalive()
检查: 当你在线程 a 中调用 threadb.join()
时,join()
方法内部会首先检查 threadb
是否还活着 (isalive()
)。如果 threadb
已经执行完毕(或者从未启动),isalive()
会返回 false
,那么 join()
方法会立即返回,线程 a 不会进行任何等待。
wait()
循环等待: 如果 isalive()
返回 true
,join()
方法会进入一个循环。在这个循环里,它会调用目标线程对象(threadb
)的 wait()
方法。
join()
方法是一个 synchronized
方法。当线程 a 调用 threadb.join()
时,它会获取 threadb
这个对象的锁。然后,join()
方法内部调用 threadb.wait()
,这会导致线程 a 释放 threadb
的锁,并进入 threadb
对象的等待集(wait set)中,状态变为 waiting
或 timed_waiting
。jvm 负责唤醒: 当目标线程 threadb
的 run()
方法执行完毕,准备退出时,java 虚拟机(jvm)会在其内部自动调用 threadb
的 notifyall()
方法。
notifyall()
会唤醒所有正在等待 threadb
对象锁的线程,当然也包括了之前因调用 join()
而等待的线程 a。重新获取锁并退出: 线程 a 被唤醒后,会尝试重新获取 threadb
的对象锁。一旦获取成功,它会从 wait()
方法返回,并退出 join()
的循环,从而结束等待,继续执行后续代码。
总结一下核心机制: join()
的实现巧妙地利用了 java 的内置锁(synchronized
)和 wait()
/notifyall()
协作机制。它将线程间的执行顺序问题,转化为了经典的“生产者-消费者”模式中的线程同步问题。
join()
的主要应用场景是协调线程间的执行顺序。当你需要确保一个或多个前置任务(在子线程中执行)完成后,主线程才能继续执行后续任务时,join()
就非常有用。
常见场景:
join()
a 所在的线程。public class joinexample { public static void main(string[] args) throws interruptedexception { system.out.println("主线程开始运行..."); thread workerthread = new thread(() -> { system.out.println("子线程开始工作..."); try { // 模拟耗时操作 thread.sleep(2000); } catch (interruptedexception e) { e.printstacktrace(); } system.out.println("子线程工作完成。"); }); workerthread.start(); // 启动子线程 system.out.println("主线程调用 join() 等待子线程..."); workerthread.join(); // 关键:主线程在此处阻塞,等待 workerthread 执行完毕 system.out.println("主线程在子线程完成后继续运行。"); } }
输出:
主线程开始运行...
主线程调用 join() 等待子线程...
子线程开始工作...
// (等待约 2 秒)
子线程工作完成。
主线程在子线程完成后继续运行。
public class multijoinexample { public static void main(string[] args) throws interruptedexception { system.out.println("主线程开始..."); thread t1 = new thread(() -> { system.out.println("线程1 开始处理..."); try { thread.sleep(1000); } catch (interruptedexception e) {} system.out.println("线程1 处理完毕。"); }); thread t2 = new thread(() -> { system.out.println("线程2 开始处理..."); try { thread.sleep(2000); } catch (interruptedexception e) {} system.out.println("线程2 处理完毕。"); }); // 启动所有线程 t1.start(); t2.start(); system.out.println("主线程等待所有子线程完成..."); // 等待 t1 和 t2 t1.join(); t2.join(); system.out.println("所有子线程处理完毕,主线程继续执行。"); } }
输出:
主线程开始...
主线程等待所有子线程完成...
线程1 开始处理...
线程2 开始处理...
// (等待约 1 秒)
线程1 处理完毕。
// (再等待约 1 秒)
线程2 处理完毕。
所有子线程处理完毕,主线程继续执行。
join()
方法会抛出 interruptedexception
。这是因为正在等待的线程(调用 join()
的线程)自身可能会被其他线程中断 (interrupt()
)。
当一个线程在 join()
等待期间被中断时,join()
方法会立即抛出 interruptedexception
。在 catch
块中,通常需要处理这个中断信号。一个好的实践是重新设置当前线程的中断状态,以便上层调用者能够知道发生了中断。
try { workerthread.join(); } catch (interruptedexception e) { // 捕获到中断异常 system.out.println("主线程在等待期间被中断了!"); // 恢复中断状态,这是一种良好的编程实践 thread.currentthread().interrupt(); }
特性 | 描述 |
---|---|
目的 | 阻塞当前线程,等待目标线程执行完毕。 |
核心原理 | 基于 synchronized 和 wait() / notifyall() 机制。 |
版本 | join() , join(long millis) , join(long millis, int nanos) 。 |
使用场景 | 需要保证线程执行顺序,如等待子任务完成、数据初始化等。 |
异常 | 抛出 interruptedexception ,需要妥善处理线程中断。 |
关键点 | t.join() 是让当前线程等待 t 线程,而不是让 t 线程等待。 |
到此这篇关于java thread中join方法使用的文章就介绍到这了,更多相关java thread中join方法使用内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
您想发表意见!!点此发布评论
版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。
发表评论