Java多线程技术二:线程间通信——join()方法的使用

news2025/1/9 16:41:48

1 概述

        在很多情况下,主线程创建并启动子线程,如果子线程中要进行大量的耗时运算,主线程往往将早于子线程结束,这时如果主线程想等待子线程执行完成后再结束,例如子线程处理一个数据,主线程要取到这个数据中的值,这个时候要用到join()方法。join()方法的作用是等待线程对象销毁。

2 学习join()前的铺垫

        在介绍join方法前,先看一个实现。

public class MyThread extends Thread{
    @Override
    public void run(){
        try{
            int secondValue = (int) (Math.random() * 10000);
            System.out.println(secondValue);
            Thread.sleep(secondValue);

        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }

}
public class Run1 {
    public static void main(String[] args) {
        MyThread t1 = new MyThread();
        t1.start();
        //Thread.sleep(?);
        System.out.println("main线程想实现:当t1线程对象执行完毕后,main在继续向下执行");
        System.out.println("但是上面sleep()方法中的值要写多少,是不确定的");
    }
}

3 用join方法解决上面的问题

        使用join方法可以解决上面的问题。

public class MyThread extends Thread{
    @Override
    public void run(){
        try{
            int secondValue = (int)(Math.random() * 10000);
            System.out.println(secondValue);
            Thread.sleep(secondValue);
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}

public class Run1 {
    public static void main(String[] args) {
        try {
            MyThread t1 = new MyThread();
            t1.start();
            t1.join();
            System.out.println("当t1执行完毕后,在执行本语句");
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}

         方法join的作用是使所属的线程对象x正常执行run方法中的任务,而使当前线程z进行无限期的阻塞,等待线程x销毁后再继续执行线程z后面的代码。也就是说,join方法具有串联执行的作用。另外,join也支持多个线程的等待,示例如下:

public class Test1 {
    static int number1 = 0;
    static int number2 = 0;
    public static void main(String[] args) throws InterruptedException {

        Thread t1 = new Thread() {
            public void run() {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                number1 = 1000;
            };
        };
        Thread t2 = new Thread() {
            public void run() {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                number2 = 2000;
            };
        };

        long beginTime = System.currentTimeMillis();
        t1.start();
        t2.start();
        System.out.println("A:" + System.currentTimeMillis());
        t1.join();
        System.out.println("B:" + System.currentTimeMillis());
        t2.join();
        System.out.println("C:" + System.currentTimeMillis());
        long endTime = System.currentTimeMillis();
        System.out.println("number1 = " + number1 + ";number2 = " + number2 + "耗时:" + (endTime - beginTime)/1000);
    }
}

        join方法具有是线程排队运行的效果,有些类似synchronzied同步的运行效果,但是它们的区别在于,join()在内部使用wait方法进行等待,会释放锁,而synchronzied关键字一直持有锁。

4 join和interrupt出现异常

        在join方法运行过程中,如果当前线程对象被中断,则当前线程出现异常。

public class ThreadA extends Thread{
    @Override
    public void run(){
        for (int i = 0; i < Integer.MAX_VALUE; i++) {
            String s = new String();
            Math.random();
        }
    }
}
public class ThreadB extends Thread{
    @Override
    public void run(){
        try {
            ThreadA a = new ThreadA();
            a.start();
            a.join();
            System.out.println("线程B在run end时打印了");
        }catch (InterruptedException e){
            System.out.println("线程B在catch中打印了");
            e.printStackTrace();
        }
    }
}
public class ThreadC extends Thread{
    private ThreadB threadB;

    public ThreadC(ThreadB threadB) {
        this.threadB = threadB;
    }

    @Override
    public void  run(){
        threadB.interrupt();
    }

}
public class Run1 {
    public static void main(String[] args) {
        try {
            ThreadB b = new ThreadB();
            b.start();
            Thread.sleep(2000);
            ThreadC c = new ThreadC(b);
            c.start();
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}

        可见,如果方法join与interrupt彼此遇到,程序会出现异常,无论它们执行的顺序是怎样的。 

5 join(long)的使用

        join(long)中的参数用于设定最长的等待时间,当线程小于long时间销毁或long时间到达并重新获得了锁时,当前线程会继续向后运行。如果没有重新获得锁,线程会一直尝试,直到获得锁为止。

public class MyThread extends Thread{
    @Override
    public void run(){
        try {
            System.out.println("开始执行run方法时间:" + Utils.data(System.currentTimeMillis()));
            Thread.sleep(3000);
            System.out.println("结束执行run方法时间:" + Utils.data(System.currentTimeMillis()));
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}
public class Run1 {
    public static void main(String[] args) {
        try {
            MyThread thread = new MyThread();
            thread.start();
            System.out.println("main方法开始执行时间:"+ Utils.data(System.currentTimeMillis()));
            thread.join(1000);
            System.out.println("main方法结束执行时间:" + Utils.data(System.currentTimeMillis()));
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}

从运行结果看,run方法执行了3秒,main方法赞提暂停了1秒。

继续新建一个Run2.java运行类,把join(1000)改成8000毫秒

public class Run2 {
    public static void main(String[] args) {
        try {
            MyThread thread = new MyThread();
            thread.start();
            System.out.println("main方法开始执行时间:"+ Utils.data(System.currentTimeMillis()));
            thread.join(8000);
            System.out.println("main方法结束执行时间:" + Utils.data(System.currentTimeMillis()));
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}

 

        从运行结果看,run方法执行了3秒,main方法暂停了3秒 。根据以上案例可以分析出,join(long)方法和sleep(long)具有相似的功能,就是使当前线程暂停指定的时间。两者的区别是:join(long)暂停的时间是可变的,取决于线程是否销毁,而sleep(long)暂停的时间是固定的。

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

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

相关文章

WordPress免费插件大全清单【2023最新】

WordPress已经成为全球范围内最受欢迎的网站建设平台之一。要让您的WordPress网站更具功能性、效率性&#xff0c;并提供卓越的用户体验&#xff0c;插件的选择与使用变得至关重要。 WordPress插件的作用 我们先理解一下插件在WordPress生态系统中的作用。插件是一种能够为Wo…

【PyTorch】softmax回归

文章目录 1. 模型与代码实现1.1. 模型1.2. 代码实现 2. Q&A 1. 模型与代码实现 1.1. 模型 背景 在分类问题中&#xff0c;模型的输出层是全连接层&#xff0c;每个类别对应一个输出。我们希望模型的输出 y ^ j \hat{y}_j y^​j​可以视为属于类 j j j的概率&#xff0c;然…

计算机网络入侵检测技术研究

摘 要 随着网络技术的发展&#xff0c;全球信息化的步伐越来越快&#xff0c;网络信息系统己成为一个单位、一个部门、一个行业&#xff0c;甚至成为一个关乎国家国计民生的基础设施&#xff0c;团此&#xff0c;网络安全就成为国防安全的重要组成部分&#xff0c;入侵检测技术…

线程的使用1

1. 创建一个线程 1.1 创建线程练习 线程实际上是应用层的概念&#xff0c;在 Linux 内核中&#xff0c;所有的调度实体都被称为任务 (task) &#xff0c; 他们之间的区别是&#xff1a;有些任务自己拥有一套完整的资源&#xff0c;而有些任务彼此之间共享一套资源 对此函数的使…

机器学习深度学学习分类模型中常用的评价指标总结记录与代码实现说明

在机器学习深度学习算法模型大开发过程中&#xff0c;免不了要对算法模型进行对应的评测分析&#xff0c;这里主要是总结记录分类任务中经常使用到的一些评价指标&#xff0c;并针对性地给出对应的代码实现&#xff0c;方便读者直接移植到自己的项目中。 【混淆矩阵】 混淆矩阵…

多模块下MyBatis官方生成器

MyBatis官方生成器 1. 依赖插件 创建generator模块 在父模块中进行版本管理 <dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.6</version> </dependency><dependency><g…

Python练习题(三)

&#x1f4d1;前言 本文主要是【Python】——Python练习题的文章&#xff0c;如果有什么需要改进的地方还请大佬指出⛺️ &#x1f3ac;作者简介&#xff1a;大家好&#xff0c;我是听风与他&#x1f947; ☁️博客首页&#xff1a;CSDN主页听风与他 &#x1f304;每日一句&am…

[足式机器人]Part2 Dr. CAN学习笔记-Ch0-1矩阵的导数运算

本文仅供学习使用 本文参考&#xff1a; B站&#xff1a;DR_CAN Dr. CAN学习笔记-Ch0-1矩阵的导数运算 1. 标量向量方程对向量求导&#xff0c;分母布局&#xff0c;分子布局1.1 标量方程对向量的导数1.2 向量方程对向量的导数 2. 案例分析&#xff0c;线性回归3. 矩阵求导的链…

el-pagination 纯前端分页

需求&#xff1a;后端把所有数据都返给前端&#xff0c;前端进行分页渲染。 实现思路&#xff1a;先把数据存储到一个大数组中&#xff0c;然后调用方法进行切割。主要使用数组的slice方法 所有代码&#xff1a; html <template><div style"padding: 20px&qu…

CSS 局限-contain

CSS 局限 CSS 局限规范的目标在于通过允许浏览器从页面的其余部分中隔离出页面子树而改善性能。若浏览器知道页面的某一部分为独立的&#xff0c;则可优化渲染并改善性能。 此外&#xff0c;此规范允许开发者标示元素究竟是否应当渲染其内容&#xff0c;以及在屏外时是否应当…

【程序员 | 交流】程序员情商修炼指南系列 (沟通是有效合作一大利器)

&#x1f935;‍♂️ 个人主页: AI_magician &#x1f4e1;主页地址&#xff1a; 作者简介&#xff1a;CSDN内容合伙人&#xff0c;全栈领域优质创作者。 &#x1f468;‍&#x1f4bb;景愿&#xff1a;旨在于能和更多的热爱计算机的伙伴一起成长&#xff01;&#xff01;&…

如何能够对使用ShaderGraph开发的Shader使用SetTextureOffset和SetTextureScale方法

假设在ShaderGraph中的纹理的引用名称为"_BaseMap"&#xff0c;同时对这个"_BaseMap"纹理使用了采样的节点"SampleTexture2D"&#xff0c;然后该采样节点的uv接入的TilingAndOffset节点&#xff0c;此时的关键步骤是新建一个Vector4属性&#xf…

HT7183 高功率异步升压转换器 中文资料

HT7183是一款高功率异步升压转换器&#xff0c;集成120mΩ功率开关管&#xff0c;为便携式系统提供G效的小尺寸处理方案。HT7183具有2.6V至5.5V输入电压范围&#xff0c;可为各类不同供电的应用提供支持。HT7183具备3A开关电流能力&#xff0c;并且能够提供高达16V的输出电压。…

实时绘画迎来大更新,本地即可部署

个人网站&#xff1a;https://tianfeng.space 前言 自此LCM公布以来&#xff0c;这一个星期在相关应用方面的更新速度nb&#xff0c;各种实时绘画工作流随之出现&#xff0c;之前还只能依赖krea内测资格使用&#xff0c;让我们来看看上周发生了那些事吧&#xff01; 网盘&am…

做外贸如何写开发信?外贸邮件营销怎么写?

外贸业务员写开发信的技巧&#xff1f;撰写客户开发信模板详解&#xff01; 外贸经营是一项竞争激烈的行业&#xff0c;写好开发信是吸引客户、建立合作关系的重要一环。蜂邮EDM将为您详细介绍如何撰写出色的开发信&#xff0c;以吸引客户的眼球&#xff0c;引领他们与您建立联…

YOLOv8独家原创改进:创新自研CPMS注意力,多尺度通道注意力具+多尺度深度可分离卷积空间注意力,全面升级CBAM

💡💡💡本文自研创新改进:自研CPMS, 多尺度通道注意力具+多尺度深度可分离卷积空间注意力,全面升级CBAM 1)作为注意力CPMS使用; 推荐指数:五星 CPMS | 亲测在多个数据集能够实现涨点,对标CBAM。 收录 YOLOv8原创自研 https://blog.csdn.net/m0_63774211/ca…

PTA 6-1 最小生成树(普里姆算法)使用递归

普利姆算法的原理 普里姆算法查找最小生成树的过程&#xff0c;采用了贪心算法的思想。对于包含 N 个顶点的连通网&#xff0c;普里姆算法每次从连通网中找出一个权值最小的边&#xff0c;这样的操作重复 N-1 次&#xff0c;由 N-1 条权值最小的边组成的生成树就是最小生成树。…

HarmonyOS 振动效果开发指导

Vibrator 开发概述 振动器模块服务最大化开放硬工最新马达器件能力&#xff0c;通过拓展原生马达服务实现振动与交互融合设计&#xff0c;打造细腻精致的一体化振动体验和差异化体验&#xff0c;提升用户交互效率和易用性、提升用户体验、增强品牌竞争力。 运作机制 Vibrato…

数据结构与算法-动态查找表

查找 &#x1f388;3动态查找表&#x1f52d;3.1二叉排序树&#x1f3c6;3.1.1二叉排序树的类定义&#x1f3c6;3.1.2二叉排序树的插入和生成&#x1f3c6;3.1.3二叉树的查找&#x1f3c6;3.1.4二叉排序树的删除 &#x1f52d;3.2平衡二叉树&#x1f3c6;3.2.1平衡二叉树的调整…

基于jsp的搜索引擎

摘 要 随着互联网的不断发展和日益普及&#xff0c;网上的信息量在迅速地增长&#xff0c;在2004年4月&#xff0c;全球Web页面的数目已经超过40亿&#xff0c;中国的网页数估计也超过了3亿。 目前人们从网上获得信息的主要工具是浏览器&#xff0c;搜索引擎在网络中占有举足轻…