异步回调之Join

news2024/11/5 15:52:13

join:异步阻塞之闷葫芦

阻塞模式实现泡茶实例首先从基础的多线程join合并实验入手.join操作的原理是阻塞当前线程,直到待合并的目标线程执行完成.

线程的合并流程

Java中线程的合并流程是:假设线程A调用线程B的join()方法去合并B线程,那么线程A进入阻塞状态,直到线程B执行完成.

泡茶例子中,主线程通过分别调用烧水线程和清洗线程的join()方法,等待烧水线程和清洗线程完成,然后主线程执行泡茶操作.流程参考图如下.

通过join()实现异步泡茶喝

通过join实现一个异步阻塞版本,参考如下.

public class JoinDemo {

    public static final int SLEEP_GAP = 500;

    public static String getCurrentThreadName() {
        return Thread.currentThread().getName();
    }

    static class HotWaterThread extends Thread {
        public HotWaterThread() {
            super("烧水--Thread");
        }

        @Override
        public void run() {
            try {
                System.out.println("洗好水壶");
                System.out.println("灌上凉水");
                System.out.println("放在火上");
                Thread.sleep(SLEEP_GAP);
                System.out.println("水开了");
            } catch (InterruptedException e) {
                System.out.println("烧水失败");
            }
            System.out.println("运行结束");
        }
    }

    static class WashThread extends Thread {
        public WashThread() {
            super("清洗--Thread");
        }

        @Override
        public void run() {
            try {
                System.out.println("洗茶壶");
                System.out.println("洗茶杯");
                System.out.println("拿茶叶");
                Thread.sleep(SLEEP_GAP);
                System.out.println("洗完了");
            } catch (InterruptedException e) {
                System.out.println("洗茶壶茶杯失败");
            }
            System.out.println("运行结束");
        }
    }

    public static void main(String[] args) {
        WashThread washThread = new WashThread();
        HotWaterThread hotWaterThread = new HotWaterThread();
        washThread.start();
        hotWaterThread.start();

        try {
            washThread.join();
            hotWaterThread.join();
            Thread.currentThread().setName("主线程");
            System.out.println("泡茶喝");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(getCurrentThreadName() + "运行结束");
    }
}

程序中有三个线程:主线程main 烧水线程HotWaterThread 清洗线程WashThread,主线程调用了这两个线程的join方法进行合并.

Join()方法详解

join方法应用场景如下:

A线程调用B线程的join方法,等待B线程执行完成,在B线程没有完成之前,A线程阻塞.

Join()方法有三个重载版本:

    /**
     * Waits for this thread to die.
     *
     * <p> An invocation of this method behaves in exactly the same
     * way as the invocation
     *
     * <blockquote>
     * {@linkplain #join(long) join}{@code (0)}
     * </blockquote>
     *
     * @throws  InterruptedException
     *          if any thread has interrupted the current thread. The
     *          <i>interrupted status</i> of the current thread is
     *          cleared when this exception is thrown.
     */
    public final void join() throws InterruptedException {
        join(0);
    }

A线程等待B线程执行结束后,A线程重新开始执行. 

    /**
     * Counts the number of stack frames in this thread. The thread must
     * be suspended.
     *
     * @return     the number of stack frames in this thread.
     * @exception  IllegalThreadStateException  if this thread is not
     *             suspended.
     * @deprecated The definition of this call depends on {@link #suspend},
     *             which is deprecated.  Further, the results of this call
     *             were never well-defined.
     */
    @Deprecated
    public native int countStackFrames();

    /**
     * Waits at most {@code millis} milliseconds for this thread to
     * die. A timeout of {@code 0} means to wait forever.
     *
     * <p> This implementation uses a loop of {@code this.wait} calls
     * conditioned on {@code this.isAlive}. As a thread terminates the
     * {@code this.notifyAll} method is invoked. It is recommended that
     * applications not use {@code wait}, {@code notify}, or
     * {@code notifyAll} on {@code Thread} instances.
     *
     * @param  millis
     *         the time to wait in milliseconds
     *
     * @throws  IllegalArgumentException
     *          if the value of {@code millis} is negative
     *
     * @throws  InterruptedException
     *          if any thread has interrupted the current thread. The
     *          <i>interrupted status</i> of the current thread is
     *          cleared when this exception is thrown.
     */
    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线程执行一段时间,最长时间为millis 毫秒,超过后就会A线程重新执行.

    /**
     * Waits at most {@code millis} milliseconds plus
     * {@code nanos} nanoseconds for this thread to die.
     *
     * <p> This implementation uses a loop of {@code this.wait} calls
     * conditioned on {@code this.isAlive}. As a thread terminates the
     * {@code this.notifyAll} method is invoked. It is recommended that
     * applications not use {@code wait}, {@code notify}, or
     * {@code notifyAll} on {@code Thread} instances.
     *
     * @param  millis
     *         the time to wait in milliseconds
     *
     * @param  nanos
     *         {@code 0-999999} additional nanoseconds to wait
     *
     * @throws  IllegalArgumentException
     *          if the value of {@code millis} is negative, or the value
     *          of {@code nanos} is not in the range {@code 0-999999}
     *
     * @throws  InterruptedException
     *          if any thread has interrupted the current thread. The
     *          <i>interrupted status</i> of the current thread is
     *          cleared when this exception is thrown.
     */
    public final synchronized void join(long millis, int nanos)
    throws InterruptedException {

        if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }

        if (nanos < 0 || nanos > 999999) {
            throw new IllegalArgumentException(
                                "nanosecond timeout value out of range");
        }

        if (nanos >= 500000 || (nanos != 0 && millis == 0)) {
            millis++;
        }

        join(millis);
    }

A线程等待B线程执行一段时间,最长时间为millis 毫秒加nanos纳秒,超过后就会A线程重新执行.

容易混淆的几点.

join()是实例方法,不是静态方法.

调用join方法时,不是thread所指向的目标线程阻塞,而是当前线程被阻塞.

只有等待的thread执行完成或者超时,当前线程才能启动执行.

总结下,join方法通过上面的源码可以看出,是不断通过检查线程是否存存活,来进行阻塞.直到被唤醒才会解除阻塞.而且join方法不能拿到返回结果,缺少很多的灵活性.所以join更多的停留在Demo演示上.

坚持读书久了,会发现自己变得温文尔雅.技术坚持久了,理解也会越来越深.

多给自己一点坚持.云淡风轻 温文尔雅是由内而外的.

如果大家喜欢我的分析的话,可以关注下我的微信公众号

心有九月星辰

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

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

相关文章

光耦合器的关键作用和创新---腾恩科技

光耦合器或光隔离器已成为电路中必不可少的器件&#xff0c;它允许信号在无需直接电接触的情况下跨不同电压域传输。这种隔离能力对于保护低压元件免受高压电路的潜在损坏至关重要。本文将仔细研究光耦合器在当今技术中发挥的独特作用&#xff0c;并探讨其在各种应用中不断扩展…

“揭开Ajax:实现无缝客户端与服务器通信的秘密”

一、概述 &#xff08;一&#xff09;概念&#xff1a; 1.概念&#xff1a; Ajax是一种web应用技术&#xff0c;可以借助客户端脚本与服务器端应用进行异步通讯&#xff0c;获取服务器数据以后&#xff0c;进行局部刷新进而提高数据响应和渲染速度。 2.开发基础&#xff1a…

自定义日志打成jar包引入项目后不生效

背景&#xff1a;写了一个请求响应日志包&#xff0c;打包后在另一个项目使用pom引入后不生效 package com.example.qqllog.aspect;import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.context.annotation.Bean;…

Java基于微信小程序的美食推荐系统(附源码,文档)

博主介绍&#xff1a;✌程序猿徐师兄、8年大厂程序员经历。全网粉丝15w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

HTML 基础标签——文本内容标签 <ul>、<ol>、<blockquote> 、<code> 等标签的用法详解

文章目录 1. 标题标签2. 段落标签3. 文本格式化标签4. 列表标签4.1 无序列表 `<ul>`4.2 有序列表 `<ol>`5. 引用标签5.1 块引用 `<blockquote>`5.2 行内引用 `<q>`5.3 作品引用 `<cite>`6. 代码和预格式文本标签6.1 代码标签 `<code>`6.2 …

一文读懂曲线调色原理

文章目录 1. 光学三原色2. 印刷三原色3. 互补关系4. 颜色混合结果5. 如何应用6. 总结 1. 光学三原色 红、绿、蓝三个颜色组成光学三原色&#xff0c;当他们三个颜色等量混合的时候就会变成白色&#xff0c;而白色代表亮&#xff0c;所以也称为加色模式。 2. 印刷三原色 青、品、…

sql专场练习(一)(最后五题 21-25)

第21题&#xff1a;找出恶意购买用户 create table sql1_21(order_id int,user_id string,order_status string,operate_time string ) row format serde org.apache.hadoop.hive.serde2.RegexSerDe with serdeproperties(input.regex(\\d)\\s(.?)\\s(.?)\\s(.?) ); load d…

如何在Linux命令行中使用GhatGPT

2、验明正身&#xff0c;证明我的所在地是国内 3、第一次提问 4、第二次提问 5、问他一首古诗 6、话不多说&#xff0c;现在来展示他的安装过程 7、输入GitHub的网址 https://github.com/aandrew-me/tgpt 8、详情页向下翻 9、到终端输入 下列命令&#xff0c;等待安装&#x…

2024年最新:阿里内部流传的大模型(LLM)面试真题

随着人工智能技术的迅猛发展&#xff0c;计算机视觉&#xff08;CV&#xff09;、自然语言处理&#xff08;NLP&#xff09;、搜索、推荐、广告推送和风险控制等领域的岗位越来越受欢迎&#xff0c;而_对于大型模型技术的掌握成为了这些岗位的标配_。 但目前公开的大模型资源还…

Redis常见面试题:ZSet底层数据结构,SDS、压缩列表ZipList、跳表SkipList

文章目录 一、Redis数据结构概述1.1 Redis有哪些数据类型1.2 Redis本质是哈希表1.3 Redis的哈希冲突与渐进式rehash1.4 数据结构底层1.4.1 简单动态字符串SDS1.4.2 双向链表&#xff08;后续已废弃&#xff09;1.4.3 压缩列表ZipList1.4.4 哈希表HashTable1.4.5 跳表SkipList1.…

【STM32】INA3221三通道电压电流采集模块,HAL库

一、简单介绍 芯片的datasheet地址&#xff1a; INA3221 三通道、高侧测量、分流和总线电压监视器&#xff0c;具有兼容 I2C 和 SMBUS 的接口 datasheet (Rev. B) 笔者所使用的INA3221是淘宝买的模块 原理图 模块的三个通道的电压都是一样&#xff0c;都是POWER。这个芯片采用…

C语言之写一个修改数组内容的函数

问题代码: 函数ltrim是为了消除buf字符数组中左边空格&#xff0c; memmove函数介绍 如果对c语言指针运用非常熟练的人,结合函数功能就会发现这个代码非常的傻逼&#xff0c;你会发现为什么需要返回&#xff0c;buf不用接收返回值&#xff0c;执行这个函数后buf中的内容就已经…

StandardThreadExecutor源码解读与使用(tomcat的线程池实现类)

&#x1f3f7;️个人主页&#xff1a;牵着猫散步的鼠鼠 &#x1f3f7;️系列专栏&#xff1a;Java源码解读-专栏 &#x1f3f7;️个人学习笔记&#xff0c;若有缺误&#xff0c;欢迎评论区指正 目录 目录 1.前言 2.线程池基础知识回顾 2.1.线程池的组成 2.2.工作流程 2…

解决pytorch问题:received an invalid combination of arguments - got

问题表现 今天跑模型时报了一个非常奇怪的错误&#xff1a; 意思是“你的lstm层输入的参数是无效的&#xff0c;要求接收参数的类型是(Tensor, tuple of (Tensor, Tensor), list of [Parameter, Parameter, Parameter, Parameter], float, int, float, bool, bool, bool)&am…

Springboot与easypoi(2):合并单元格、二级表头、动态导出

一、纵向合并单元格 使用Excel(needMerge true)标记的属性表示此单元格需要合并。ExcelCollection表示一对多的集合&#xff0c;下面是合并单元格案例。 实体类 企业类&#xff1a; package com.ywz.entity;import cn.afterturn.easypoi.excel.annotation.Excel; import cn.…

vue3 + ts + element-plus 二次封装 el-table

一、实现效果&#xff1a; &#xff08;1&#xff09;数据为空时&#xff1a; &#xff08;2&#xff09;有数据时&#xff1a;存在数据合并&#xff1b;可自定义表头和列的内容 &#xff08;3&#xff09;新增行&#xff1a; &#xff08;4&#xff09;删除行&#xff1a; &a…

Python CGI编程-cookie的设置、检索

设置检索 其他&#xff1a; 1. http.cookies和http.cookiejar区别&#xff1a; http.cookies主要用于创建和操作单个cookie对象&#xff0c;适用于需要精细控制单个cookie属性的场景。http.cookiejar则用于管理多个cookie&#xff0c;适用于需要自动处理多个请求和响应中的coo…

k8s 二进制部署安装(三)

目录 部署Calico Calico 工作原理 部署Calico 部署CoreDNS 负载均衡部署 部署dashboard 部署Calico 安装步骤来到 CNI 网络组件 &#xff0c;在&#xff08;二&#xff09;中我们安装了flannel&#xff0c;现在我们要尝试安装另一网络组件Calico calico 不使用隧道或NAT…

idea 创建web工程

模块添加Add Framework Support web Application 改为4.0以上

Linux系列-进程的概念

&#x1f308;个人主页&#xff1a;羽晨同学 &#x1f4ab;个人格言:“成为自己未来的主人~” 这篇文章&#xff0c;我们主要分析一下进程。 之前&#xff0c;我们讲过了冯诺依曼体系架构&#xff0c; 我们常见的计算机&#xff0c;像笔记本&#xff0c;或者不常见的计算机…