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

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)暂停的时间是固定的。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

如何入驻抖音本地生活服务商,门槛太高怎么办?

随着抖音本地生活服务市场的逐渐成熟&#xff0c;越来越多平台开始涉及本地生活服务领域&#xff0c;而本地生活服务商成了一个香窝窝&#xff0c;为了保护用户权益和平台生态&#xff0c;对入驻入驻抖音本地生活服务商的条件及审核也越来越严格&#xff0c;这让很多想成为抖音…

Mysql的索引详解

1.索引的分类 1.按照功能来分&#xff0c;可以分为主键索引、唯一索引、普通索引、全文索引 2.按照索引字段个数来分&#xff0c;可以分为单列索引、联合索引 3.按照物理实现方式来分&#xff0c;可以聚簇索引、非聚簇索引 2.适合添加索引的场景 1.具有唯一性约束的字段。 2…

Matlab论文插图绘制模板第129期—函数网格曲面图

在之前的文章中&#xff0c;分享了Matlab函数折线图的绘制模板&#xff1a; 函数三维折线图&#xff1a; 进一步&#xff0c;再来分享一下函数网格曲面图。 先来看一下成品效果&#xff1a; 特别提示&#xff1a;本期内容『数据代码』已上传资源群中&#xff0c;加群的朋友请自…

直击2023云栖大会-大模型时代到来:“计算,为了无法计算的价值”

2023年的云栖大会以“计算&#xff0c;为了无法计算的价值”为主题&#xff0c;强调了计算技术在现代社会中的重要性&#xff0c;特别是在大模型时代到来的背景下。 大模型时代指的是以深度学习为代表的人工智能技术的快速发展&#xff0c;这些技术需要大量的计算资源来训练和优…

算法设计与实现--动态规划篇

什么是动态规划算法 动态规划算法是一种求解复杂问题的方法&#xff0c;通过将原问题分解为相对简单的子问题来求解。其基本思想是将待求解的问题分解为若干个子问题&#xff08;阶段&#xff09;&#xff0c;按顺序求解子阶段&#xff0c;前一子问题的解&#xff0c;为后一子…

uniapp:如何使用uCharts

目录 第一章 前言 第二章 安装插件uCharts 第三章 使用uCharts 第四章 注意 第一章 前言 需求&#xff1a;这是很久之前的一个项目的需求了&#xff0c;当时我刚接触app&#xff0c;有这么一个需求&#xff0c;在uniapp写的app项目中做一些图表统计&#xff0c;最开始以为…

设备巡检的内容有哪些?巡检注意事项及巡检要点?

本文将为大家讲解&#xff1a;设备巡检的内容有哪些&#xff1f;巡检注意事项及巡检要点&#xff1f; 每个制造型企业都有成百上千的设备需要定期的巡检。在生产制造加工类企业中&#xff0c;设备的巡检、维修及保养工作是保障生产安全和效率的重要内容之一。过去因为问题设备漏…

【零基础入门Python】Python If Else流程控制

✍面向读者&#xff1a;所有人 ✍所属专栏&#xff1a;零基础入门Pythonhttps://blog.csdn.net/arthas777/category_12455877.html Python if语句 Python if语句的流程图 Python if语句示例 Python If-Else Statement Python if else语句的流程图 使用Python if-else语句 …

MDK ARM环境下的伪指令的测试

目录 测试目标&#xff1a; 测试代码&#xff1a; 1. start.s 2. align.s 测试结果&#xff1a; 1 .ldr伪指令的测试结果: 2 .align伪操作测试结果: 结果分析&#xff1a; 测试目标&#xff1a; 熟悉ARM处理器的伪指令&#xff0c;本次实验主要来练习ldr伪指令和align…

Python代码部署的三种加密方案,其中一种你肯定不知道

文章目录 前言一、代码混淆二、代码打包三、代码编译3.1 pyarmor快速使用3.2 pyarmor进阶使用关于Python技术储备一、Python所有方向的学习路线二、Python基础学习视频三、精品Python学习书籍四、Python工具包项目源码合集①Python工具包②Python实战案例③Python小游戏源码五、…

Docker Image(镜像)——5

目录&#xff1a; Docker 镜像是什么镜像生活案例镜像分层生活案例为什么需要镜像镜像命令详解 镜像命令清单docker imagesdocker tagdocker pulldocker pushdocker rmidocker savedocker loaddocker historydocker importdocker image prunedocker build镜像操作案例 查找镜像…

02_W5500网络初始化

如何与W5500通信&#xff1f; 我们在W5500介绍中可以看到W5500支持SPI通信协议&#xff0c;如果对SPI通信协议还不太了解&#xff0c;请转 SPI数据帧&#xff1a; W5500 的 SPI 数据帧包括了 16 位地址段的偏移地址&#xff0c; 8 位控制段和 N 字节数据段。 如图所示…

10分钟带你学会python模块和包的使用

如果你用过 Python&#xff0c;那么你一定用过 import 关键字加载过各式各样的模块。但你是否熟悉 Python 中的模块与包的概念呢&#xff1f;或者&#xff0c;以下几个问题&#xff0c;你是否有明确的答案&#xff1f; 什么是模块&#xff1f;什么又是包&#xff1f;from matp…

Educational Codeforces Round 159 (Rated for Div. 2)(A~E)

A - Binary Imbalance 题意&#xff1a;给定一个01串&#xff0c;你能够在相邻相同字符中插入‘1’,在相邻不同字符中插入‘0’&#xff0c;求最终能否使得0的数量严格大于1的数量。 思路&#xff1a;可以发现&#xff0c;当出现了‘01’或者‘10’子序列时&#xff0c;能够无…

分享74个节日PPT,总有一款适合您

分享74个节日PPT&#xff0c;总有一款适合您 74个节日PPT下载链接&#xff1a;https://pan.baidu.com/s/18YHKkyJsplx-Gjj7ofpFrg?pwd6666 提取码&#xff1a;6666 Python采集代码下载链接&#xff1a;采集代码.zip - 蓝奏云 学习知识费力气&#xff0c;收集整理更不易…

机器学习---环境准备

一、pySpark环境准备 1、window配置python环境变量 window安装python&#xff0c;配置python环境变量。安装python后,在环境变量path中加入安装的路径&#xff0c;cmd中输入python&#xff0c;检验python是否安装成功。 注意&#xff1a;如果使用的是anaconda安装的python环境…

【滑动窗口】长度最小的数组

长度最小的数组 长度最小的数组 文章目录 长度最小的数组题目描述解法暴力解法滑动窗口Java示例代码c示例代码 题目描述 给定一个含有 n 个正整数的数组和一个正整数 target 。 找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl1, ..., numsr-1, num…

若依微服务项目整合rocketMq

原文链接&#xff1a;ttps://mp.weixin.qq.com/s/IYdo_suKvvReqCiEKjCeHw 第一步下载若依项目 第二步安装rocketMq&#xff08;推荐在linux使用docker部署比较快&#xff09; 第二步新建一个生产者模块儿&#xff0c;再建一个消费者模块 第四步在getway模块中配置接口映射规…

【高效开发工具系列】gson入门使用

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

HT4822 无输出隔直电容 立体声耳机放大器 中文资料

HT4822是一款无需输出隔直电容的立体声耳机放大器。HT4822支持差分和单端的模拟信号输入。 HT4822在3.6V供电下&#xff0c;THDN 1%&#xff0c;32ohm负载时能提供80mW的输出。其具有低至0.007%的THDN。HT4822能在2.5V-6.0V电源条件下工作&#xff0c;具有过热保护和欠压保护等…