多线程-线程通信(wait-notify,await-single,park-unpark)

2023-11-01

在多线程场景中,如有些线程需要依赖另外线程的结果而继续执行,如多个线程处理请求,有的处理的快有点慢。快的需要等待慢的线程结果一起提交执行结果。都会涉及到线程间的通信,就是A线程告知B线程处理的结果是怎么样,B线程再执行对应逻辑。通信比较经典的就是采用等待通知模式,当然还有join,volilate等也可作为通信手段。本文重点讲下API层面的通信。

举个例子,三个线程T1,T2,MAIN的场景,T1因为条件不满足进入等待状态,等待其他线程的唤醒(可理解为孩子吃饭没辣条自己关上门在房间里等待辣条)。T2的工作就是唤醒T1线程,但是没满足T1的条件。所以T1还是会进入等待状态(可理解为爸爸为了骗孩子吃饭去敲门叫孩子,说有辣条了,但此时其实没辣条的,所以孩子出门看了一眼,又回去房间里等待了)。MAIN线程也是唤醒线程,并且还满足T1的条件,这时T1就会正常执行。(可理解为妈妈过了一段时间看不下去了,去买了辣条并叫孩子出来吃饭,孩子出来看到有辣条了就开心的吃起来饭

(1)基于Object的wait-notify,此方法需要与syncronized代码块共用。因为底层是采用monitor对象的waitSet去实现。

@Slf4j
class WaitNotify {
    private static boolean flag = false;
    private static Object lock = new Object();
    public static void main(String[] args) {
       new Thread(()->{
            synchronized (lock) {
                while (!flag) {
                    log.info("没辣条不想吃饭,进房间等待");
                    try {
                        lock.wait(); //释放锁
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                log.info("哈哈!有辣条吃饭真香");
            }
        },"孩子").start();

        new Thread(()->{
            synchronized (lock) {
                log.info("爸爸给你买辣条了,出来吃饭");
                lock.notify();
            }
        },"爸爸").start();

        SleepUtils.sleep(2);
        synchronized (lock) {
            log.info("妈妈给你买辣条了,出来吃饭");
            flag = true;
            lock.notify();
        }
    }
}

 (2)基于ReentrantLock的await,single。语法比较繁琐,需要先获取到lock,然后要建立一个休息室供线程休息,类似与monitor中的waitSet。最后需要unlock释放锁。

@Slf4j
class AwaitSingle{
    private static boolean flag = false;
    private static ReentrantLock lock = new ReentrantLock();
    static Condition condition = lock.newCondition(); //休息室
    public static void main(String[] args) {
        new Thread(()-> {
            lock.lock();
            try {
                while (!flag) {
                    log.info("没辣条不想吃饭,进房间等待");
                    try {
                        condition.await();//进入休息室等待
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                log.info("哈哈!有辣条吃饭真香");
            } finally {
                lock.unlock();
            }
        },"孩子").start();

        new Thread(()->{
            lock.lock();
            try{
                log.info("爸爸给你买辣条了,出来吃饭");
                condition.signal(); //唤醒
            } finally {
                lock.unlock();
            }
        },"爸爸").start();

        SleepUtils.sleep(2);
        lock.lock();
        try {
            log.info("妈妈给你买辣条了,出来吃饭");
            flag = true;
            condition.signal();
        }finally {
            lock.unlock();
        }
    }
}

(3)基于LockSupport的park,unpark方法。此方法要注意的是如先调用unpark,则第一次park时不会被阻塞。第二次才会。但并不会unpark调了多次就可以使park失效多次,调用多次unpark也只会失效一次park。

@Slf4j
class Park{
    private static boolean flag = false;
    public static void main(String[] args) {
        Thread t1 = new Thread(()-> {
                while (!flag) {
                    log.info("没辣条不想吃饭,进房间等待");
                    LockSupport.park();
                }
            log.info("哈哈!有辣条吃饭真香");
        },"孩子");
        t1.start();

        new Thread(()->{
            log.info("爸爸给你买辣条了,出来吃饭");
                LockSupport.unpark(t1);
        },"爸爸").start();
        SleepUtils.sleep(2);

        log.info("妈妈给你买辣条了,出来吃饭");
        flag = true;
        LockSupport.unpark(t1);
    }
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

多线程-线程通信(wait-notify,await-single,park-unpark) 的相关文章

随机推荐

  • 如何给6个整数的一维数组某个元素赋值_C++基础知识篇:C++ 数组

    C 支持数组数据结构 它可以存储一个固定大小的相同类型元素的顺序集合 数组是用来存储一系列数据 但它往往被认为是一系列相同类型的变量 数组的声明并不是声明一个个单独的变量 比如 number0 number1 number99 而是声明一个
  • 用好这 28 个工具,开发效率爆涨|云效工程师指北

    大家好 我是秦世成 我在云效负责制品仓库Packages的开发工作 作为一个有多年经验的资深CRUD后端工程师 使用过很多日常开发所需的工具软件 其中不少能堪称为 神器 这些 神器 能极大的提升日常开发的效率 小到一个复制粘贴操作 大到开发
  • Wireshark

    抓包工具 抓包工具是拦截查看网络数据包内容的软件 抓包工具由于其可以对数据通信过程中的所有lP报文实施捕获并进行逐层拆包分析 一直是传统固网数通维护工作中罐常用的故障排查工具 业内 流行的抓包软件有很多 Wireshark SnifferP
  • 【vue】$set怎么使用

    vue中在data 里的数据才是响应式的 有的场景 比如说后端返回的接口对象里 想再增加一个属性 作为响应式 这时候可以用到 set添加 set总共三个参数 第一个为当前对象 第二个为属性名 第三个为属性值
  • nebula graph 常用命令(updating)

    文章目录 管理Storage主机 空间 创建标签 边 点 增 改 删除点和边 索引 创建索引 重建索引 drop tag 查询 match go FETCH LOOKUP 统计 管理Storage主机 从 3 0 0 版本开始 在配置文件中
  • 循环遍历的区别

    循环遍历的区别 forEach 直接循环数组 没有返回值 如何结束循环 是结束本次循环是可以使用return 但是结束全部循环return无效 原因 好像是因为forEach不管符不符合都会走完所有的循环 所以return结束本次循环后 会
  • 【markdown工具配合图床】PicGo图床配置教程,一秒读懂配置

    前言 看到这篇文章的大佬 我默认大家都会配置git 已经配置好ssh公钥 此时你看到的这篇文章就是基于markdown工具 VSCode Typora 编写的 PicGo作为图床转换工具 并配合gitee作为图片服务器 仓库 个人设置找到私
  • tms web core 调用webapi的方法

    webhttprequest组件属性设置 header Cache Control no cache no store must revalidate Content Type application x www form urlencod
  • 紫书《算法竞赛入门经典》

    紫书 算法竞赛入门经典 题目一览 第3章 数组和字符串 例题 UVA 272 TEX Quotes UVA 10082 WERTYU UVA 401 Palindromes UVA 340 Master Mind Hints UVA 158
  • 利用StringEscapeUtils对字符串进行各种转义与反转义(Java)

    转载自 Java我人生 陈磊兴 原文出处 http blog csdn net chenleixing article details 43456987 apache工具包common lang中有一个很有用的处理字符串的工具类 其中之一就
  • renren-generator项目启动后无法打开网页

    解决
  • JavaScript对象的定义以及创建对象的三种方式和遍历对象的介绍以及相对应的案例

    JavaScript对象 1 什么是对象 在JavaScript中 对象是一组无序的相关属性和方法的集合 所有的事物都是对象 例如字符串 数值 数组 函数等 对象是由属性和方法组成的 属性 事物的特征 在对象中用属性来表示 常用名词 方法
  • ElasticSearch 之 _score

    ElasticSearch 之 score 1 什么是 score 2 布尔模型 3 词频 逆向文档频率 TF IDF 3 1 词频 3 2 逆向文档频率 3 3 字段长度归一值 3 4 结合使用 4 向量空间模型 5 Lucene的实用评
  • MySQL免安装版下载及安装(完整版)

    1 安装包下载 1 进入官网下载 MySQL Download MySQL Community Server Archived Versions 2 压缩包解压到你要安装的位置 2 MySQL配置 1 以管理员身份打开命令 2 跳转到MyS
  • 圆形图片

    public class RoundImageView extends ImageView public RoundImageView Context context super context TODO Auto generated co
  • 期货,实例讲述

    说到 期货 有人马上就会想到一大堆的粮食或者金属品的满天飞 其实不然 如果要每个人都抱一大堆的粮食回家的话我想经纪公司存在也没有它实质的意义了 其实对于大多数的投机者来说 期货 就和 股票 一样 都是一种低买高卖的挣钱工具 它并不需要你把一
  • 分布式复习1~3章

    参考 学校ppt 整体 爹 https zhuanlan zhihu com p 341814546 时间和时钟 https blog csdn net fragile98 article details 113695334 分布式系统的时
  • 利用ESP8266模块实现远程用手机控制开关

    利用ESP8266模块实现远程用手机控制开关 文章目录 前言 一 ESP8266是什么 二 使用步骤 1 密钥与核心库 2 连接Wi Fi 3 手机端控制函数 总结 插入链接与图片 列表 前言 随着万物联网的时代到来 通过互联网来控制已经越
  • AIGC 的概念与内涵

    导读 目前 对AIGC这一概念的界定 尚无统一规范的定义 国内产学研各界对于AIGC的理解是 继专业生成内容 ProfessionalGeneratedContent PGC 和用户生成内容 UserGeneratedContent UGC
  • 多线程-线程通信(wait-notify,await-single,park-unpark)

    在多线程场景中 如有些线程需要依赖另外线程的结果而继续执行 如多个线程处理请求 有的处理的快有点慢 快的需要等待慢的线程结果一起提交执行结果 都会涉及到线程间的通信 就是A线程告知B线程处理的结果是怎么样 B线程再执行对应逻辑 通信比较经典