Java 中的 Thread.join() 方法详解

介绍

本文基于 Java 8 进行编写,可能与您使用的 Java 版本有所不同,请注意版本差异。

在多线程编程中,线程的管理和协调是一个重要课题。Java 提供了多种机制来实现线程之间的协调,其中之一就是 Thread.join() 方法。join() 方法允许一个线程等待另一个线程完成,这在很多场景中是非常有用的。例如,当我们需要确保某个任务在继续之前必须先完成另一个任务时,join() 方法就是一个很好的选择。

代码演示

为了更好地理解 join() 方法的使用,我们来看一个简单的代码示例。

public class JoinExample extends Thread {public void run() {for(int i = 1; i <= 5; i++) {try {Thread.sleep(500);} catch(InterruptedException e) {System.out.println(e);}System.out.println(i);}}public static void main(String[] args) {JoinExample t1 = new JoinExample();JoinExample t2 = new JoinExample();JoinExample t3 = new JoinExample();t1.start();try {t1.join();} catch(InterruptedException e) {System.out.println(e);}t2.start();t3.start();}
}

在上述代码中,主线程启动了 JoinExample 线程 t1,并调用了 t1.join(),这使得主线程在 t1 完成之前不会继续执行。当 t1 完成后,主线程才会继续启动 t2 和 t3。

join() 工作机制

join() 方法让调用线程进入等待状态,直到目标线程完成或者被中断。其内部实现依赖于 Object 类的 wait() 方法,因此在等待期间调用线程会释放 CPU 资源,以便其他线程能够执行。通过调用 join() 方法,可以确保一个线程的执行顺序,这在某些需要依赖线程执行结果的场景中非常重要。

join() 源码解析

在 Java 8 中,Thread.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");}// 如果传入的超时时间为0,表示无限等待,直到目标线程结束if (millis == 0) {while (isAlive()) {// 无限期等待目标线程结束wait(0);}} else {// 如果传入的超时时间大于0,则在目标线程结束或者超时时间到达之前等待while (isAlive()) {// 计算剩余的等待时间long delay = millis - now;if (delay <= 0) {// 如果剩余时间小于等于0,跳出循环break;}// 等待剩余时间wait(delay);// 更新当前时间now = System.currentTimeMillis() - base;}}
}

join 方法是 Java 中 Thread 类提供的一个关键方法,用于使一个线程等待另一个线程的完成。在实现上,join 方法通过调用 Object 类的 wait 方法实现了等待机制。其逻辑可以分为以下几步:

  1. 记录当前的基准时间,用于后续计算等待时间。
  2. 检查传入的超时时间是否为负数,若是则抛出异常。
  3. 根据传入的超时时间,决定是进行无限等待还是有限等待:
    • 若超时时间为0,则无限期等待目标线程结束。
    • 若超时时间大于0,则计算剩余的等待时间,并在目标线程结束或超时前等待。

通过这些步骤,join 方法能够灵活地处理不同的等待时间,并在目标线程结束或者指定的超时时间到达之前,将调用线程置于等待状态。这一机制在多线程编程中非常有用,特别是在需要确保某个线程在继续执行之前等待另一个线程完成的场景下。

join()wait() 的对比研究

  1. 定义

    • join()Thread 类的方法,用于等待另一个线程完成。
    • wait()Object 类的方法,用于使线程等待某个条件发生。
  2. 使用场景

    • join() 通常用于一个线程等待另一个线程完成。
    • wait() 通常与 notify()notifyAll() 一起使用,用于线程间的通信。
  3. 锁定

    • join() 内部使用 wait() 实现,因此会释放持有的锁。
    • wait() 需要在同步块中调用,同样会释放锁。

join() 方法的常见使用场景

  • 线程依赖关系:当一个线程的执行依赖于另一个线程的完成时,可以使用 join() 方法。例如,在并行处理多个任务时,主线程可能需要等待所有子线程完成后再继续执行。

    • Fork/Join 框架:在并行计算中,将任务拆分成子任务,主线程等待所有子任务完成后再继续执行。
    • Spring 异步任务处理:在使用 @Async 注解时,主线程需要等待所有异步任务完成后再继续执行。
    • Apache Spark 分布式计算:在分布式数据处理任务中,主线程需要等待所有子任务完成后再汇总结果。
    • Java Concurrency (ExecutorService):在并行任务处理中,主线程需要等待所有线程池中的任务完成后再继续执行。
  • 同步初始化:在某些情况下,某个线程需要初始化一些资源,其他线程需要等待这些资源初始化完成后才能继续工作。这时可以使用 join() 方法来实现同步初始化。

    • Spring Framework:在使用异步任务时,主线程需要等待资源初始化完成后才能继续执行其他任务。
    • Hibernate:初始化数据库连接或 SessionFactory 时,主线程需要等待这些初始化操作完成后,才能进行数据库操作。
    • Apache Hadoop:初始化 HDFS 文件系统或 MapReduce 框架时,线程需要等待资源初始化完成后,才能开始数据处理任务。
    • Apache Kafka:启动消费者和生产者时,消费者线程需要等待生产者初始化 Kafka 连接和主题配置完成后,才能开始消费消息。
    • Android:在 Android 应用开发中,UI 线程需要等待后台线程初始化数据或加载资源完成后,才能进行界面更新操作。
    • Java EE (Jakarta EE):初始化 JNDI 资源或启动 EJB 容器时,其他线程需要等待这些资源初始化完成后,才能进行后续操作。
  • 简化复杂流程控制:在复杂的多线程流程中,使用 join() 可以简化线程之间的协调和控制,确保流程按预期进行。

    • Fork/Join 框架:在处理分而治之的任务时,使用 join() 可以简化任务分割和结果合并的控制流程。
    • Spring Batch:在批处理任务中,主线程需要等待所有步骤完成后再进行下一步操作,确保批处理流程的有序进行。
    • Apache Kafka:在消费者和生产者处理流程中,使用 join() 确保消息处理的顺序和数据的一致性。
    • Java Concurrency (ExecutorService):在复杂的并发任务处理流程中,使用 join() 可以协调多个线程的执行顺序,确保任务按预期进行。

join() 方法的注意事项和常见问题

  • 可能引起死锁:如果不小心使用 join() 方法,可能会引起死锁。例如,两个线程相互等待对方完成就会导致死锁。
  • 中断处理:在使用 join() 方法时,需要处理 InterruptedException 异常,以确保线程可以响应中断。
  • 性能影响:频繁使用 join() 方法可能会影响程序的性能,尤其是在等待时间较长的情况下。

国内外资源参考

以下是一些参考资源,提供了更多关于 join() 方法的信息和示例:

  1. Baeldung - 提供了详细的教程和示例。
  2. GeeksforGeeks - 讨论了 join() 方法的概念和使用。
  3. Javatpoint - 详细解释了 join() 方法的参数和异常处理。
  4. HowToDoInJava - 提供了多个示例和解释。
  5. Javaguides - 讨论了 join() 方法的用法和实现细节。
  6. CSDN博客 - 提供了大量关于 join() 方法的深入解析和示例。
  7. InfoQ - 讨论了多线程编程的各种技术和实践。
  8. Stack Overflow - 提供了开发者之间的问答和讨论。
  9. Oracle官方文档 - 提供了 Thread 类的官方说明和详细文档。
  10. 俄罗斯编程论坛 - 讨论了多线程编程的各种技术和实践。

结论

Thread.join() 方法在 Java 多线程编程中是一个非常有用的工具。它允许一个线程等待另一个线程完成,从而可以更好地管理线程的执行顺序。通过理解 join() 方法的工作机制、源码实现以及与 wait() 方法的对比,我们可以更好地应用这一工具来实现复杂的多线程应用程序。

在实际使用 join() 方法时,务必要注意可能出现的死锁和性能问题,合理使用异常处理和超时设置,以确保程序的稳定性和效率。通过参考国内外的各种资源,我们可以深入了解 join() 方法的各个方面,提升我们的多线程编程能力。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/24924.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

实战分析:记录一下线上OOM排查(原创)

记录背景 公司仓库系统经常反馈出现系统使用不了503的情况&#xff0c;自动挂掉。 启动脚本添加命令 以为是程序发生OOM导致内存溢出&#xff0c;添加命令&#xff0c;发生内存溢出输出文件 -XX:HeapDumpOnOutOfMemoryError -XX:ErrorFile./errorfile.log -XX:HeapDumpPath.…

计算文件md5

在开发过程中&#xff0c;经常要验证文件是否是同一个文件&#xff0c;或者文件是否被修改&#xff0c;可以通过计算md5值来比对文件是否改变。 使用方法 md5sum 文件名 # 67ed5ca4a19a2d9682b680cb30c9be64 *aaa.mp4## 67ed5ca4a19a2d9682b680cb30c9be64 就是aaa.mp4的MD5值…

Windows无法安装到这个硬盘空间。选定的分区上启用了BitLocker驱动器加密。请在控制面板中暂停(也称为禁用)BitLocker,然后重新开始安装。

我们安装操作系统的时候&#xff0c;到了选择安装分区的地方&#xff0c;我们选中的分区提示“无法在驱动器的分区上安装Windows”&#xff0c;然后我们点击显示详细信息&#xff0c;提示如图下所示 分析原因&#xff0c;可能是之前的分区未进行格式化。但是这个时候我们无法格…

Maven的安装与配置要点和难点常见报错和解决方案

Maven的安装与配置过程可以概括为以下几个步骤: 1. 安装前提 安装JDK:Maven需要Java环境,因此首先需要安装JDK。通常建议使用与Maven兼容的JDK版本,如JDK 1.8或更高版本。 2. 下载Maven 访问Maven官网:从Maven的官方网站下载最新版本的Maven。确保选择与操作系统兼容的…

【Python预处理系列】深入理解过采样技术及其Python实现

目录 一、过采样简介 二、过采样的实现方法 三、过采样和欠采样是数据增强吗 四、Python实现SMOTE过采样 &#xff08;一) 生成不平衡数据集 &#xff08;二&#xff09; 将数据集转换为DataFrame&#xff0c;便于展示 &#xff08;三) 应用SMOTE算法进行过采样 &…

JavaScript html css 字符串对象

字符串对象 字符串所有的方法&#xff0c;都不会修改字符串本身&#xff08;字符串是不可变的&#xff09;&#xff0c;操作完成会返回一个新的字符串。 length属性 作用&#xff1a; 获取字符串长度 示例&#xff1a; <span style"background-color:#f8f8f8&qu…

阿里云ECS服务器部署javaweb项目实操

在阿里云ECS实例上部署Java Web项目涉及几个主要步骤&#xff1a;创建和配置ECS实例、安装必要的软件&#xff08;JDK、Web服务器、数据库等&#xff09;、部署Java Web应用程序以及配置防火墙和安全组。以下是详细的步骤&#xff1a; 步骤1&#xff1a;创建ECS实例 登录阿里云…

【Centos7】CentOS 7下的PyTorch安装策略:高效实践指南

【Centos7】CentOS 7下的PyTorch安装策略&#xff1a;高效实践指南 大家好 我是寸铁&#x1f44a; 总结了一篇【Centos7】CentOS 7下的PyTorch安装策略&#xff1a;高效实践指南✨ 喜欢的小伙伴可以点点关注 &#x1f49d; 前言 由于需要跑深度学习&#xff0c;要用到pytorch&a…

java的序列化与反序列化

一、定义 Java序列化和反序列化&#xff1a;序列化就是指把Java对象转换为字节序列的过程。&#xff08;例如将一个类转化为json类型&#xff09;反序列化就是指把字节序列恢复为Java对象的过程。 在Java实际运用中&#xff0c;,许多方面应用序列化反序列化——持久化、通信、…

重塑楼宇管理:智慧管控可视化开启高效新篇章

借助图扑智慧楼宇管控可视化技术&#xff0c;实现实时监控与智能化管理&#xff0c;快速响应潜在问题&#xff0c;确保楼宇安全、节能和高效运行。

Git之解决重复输入用户名和密码(三十九)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

快速入门Linux及使用VSCode远程连接Linux服务器

在当前的技术环境中&#xff0c;Linux操作系统因其强大的功能和灵活性而广受欢迎。无论你是开发人员、系统管理员还是技术爱好者&#xff0c;学习Linux都是提升技术技能的重要一步。本文将介绍如何快速入门Linux&#xff0c;并使用Visual Studio Code&#xff08;VSCode&#x…

时光正好保剑锋的抱治百病与成年人的世界

《时光正好》&#xff1a;保剑锋的“抱治百病”与成年人的世界在繁忙的都市里&#xff0c;每个角落上演着各自的人生戏码。而在这些戏码中&#xff0c;由保剑锋主演的《时光正好》无疑成为了近期引人注目的焦点。这部电视剧以其真实而深刻的剧情&#xff0c;让我们看到了成年人…

深入了解Linux中的db_dump185命令

深入了解Linux中的db_dump185命令 在Linux系统中&#xff0c;db_dump185可能不是一个广为人知的命令&#xff0c;但它对于某些特定的数据库或文件系统任务来说却是一个非常有价值的工具。特别是当你与旧版的Berkeley DB数据库或类似的存储机制打交道时&#xff0c;db_dump185可…

SpringBoot+Vue实现前后端分离基本的环境搭建

目录 一、Vue项目的搭建 &#xff08;1&#xff09;基于vite创建vue项目 &#xff08;2&#xff09;引入elementplus &#xff08;3&#xff09;启动后端服务&#xff0c;并测试 二、SpringBoot项目的搭建 &#xff08;1&#xff09;通过idea创建SpringBoot项目 &#x…

有效的括号(oj题)

一、题目链接 https://leetcode.cn/problems/valid-parentheses/submissions/538110206 二、题目思路 利用栈的性质&#xff0c;后进先出 1.依次读取字符串&#xff0c;判断是否为左括号&#xff0c;如果是&#xff0c;就将其入栈。 2.如果读取的不是左括号&#xff0c;就说…

【网络教程】Iptables官方教程-学习笔记7-简单理解IPTABLES规则的作用流程

前面学习了IPTABLES的所有功能介绍后&#xff0c;一个Linux设备里的IPTABLES规则集是如何运行的&#xff0c;这里简单做个介绍。 在Linux设备里输入"iptables -nvl",得到该设备的所有防火墙规则&#xff0c;得到的结果中可以看到这个设备防火墙里所有的链以及链里的…

Git从入门到放弃

由于我的Git学的不太好&#xff0c;所以为了能够将以后我的学习笔记能够整理的更好&#xff0c;我先要系统的学习一下git&#xff0c;文章由此产生。 文章笔记源自尚硅谷Git入门到精通全套教程视频内容 1 进入官网 学习新技术的第一步需要熟悉官网&#xff0c;Git也不例外。ht…

【区分vue2和vue3下的element UI ¶Upload 上传组件,分别详细介绍属性,事件,方法如何使用,并举例】

在 Vue 2 中&#xff0c;我们通常使用 Element UI 的 el-upload 组件来实现文件上传功能。然而&#xff0c;在 Vue 3 中&#xff0c;由于 Element UI 没有官方支持 Vue 3 的版本&#xff0c;我们通常会使用 Element Plus&#xff08;Element UI 的 Vue 3 版本&#xff09;的 el…

海豚调度器调用api接口启动工作流(亲试可用)

一、前言 在大数据时代,工作流调度器成为了数据管道和ETL任务中不可或缺的工具。DolphinScheduler作为一款强大的工作流调度器,支持多种任务类型和工作流的可视化管理。除了通过Web界面操作外,DolphinScheduler也提供了API接口,使得第三方系统集成和自动化脚本调用成为可能…