当前位置: 首页 > news >正文

Java_线程通信

一、线程通信

首先,什么是线程通信呢?

  • 当多个线程共同操作共享资源时,线程间通过某种方式互相告知自己的状态,以相互协调,避免无效的资源挣抢。

线程通信的常见模式:是生产者与消费者模型

  • 生产者线程负责生成数据
  • 消费者线程负责消费生产者生成的数据
  • 注意:生产者生产完数据后应该让自己等待,通知其他消费者消费;消费者消费完数据之后应该让自己等待,同时通知生产者生成。

比如下面案例中,有3个厨师(生产者线程),两个顾客(消费者线程)。
在这里插入图片描述
接下来,我们先分析一下完成这个案例的思路

1.先确定在这个案例中,什么是共享数据?答:这里案例中桌子是共享数据,因为厨师和顾客都需要对桌子上的包子进行操作。2.再确定有那几条线程?哪个是生产者,哪个是消费者?答:厨师是生产者线程,3条生产者线程; 顾客是消费者线程,2条消费者线程3.什么时候将哪一个线程设置为什么状态生产者线程(厨师)放包子:1)先判断是否有包子2)没有包子时,厨师开始做包子, 做完之后把别人唤醒,然后让自己等待3)有包子时,不做包子了,直接唤醒别人、然后让自己等待消费者线程(顾客)吃包子:1)先判断是否有包子2)有包子时,顾客开始吃包子, 吃完之后把别人唤醒,然后让自己等待3)没有包子时,不吃包子了,直接唤醒别人、然后让自己等待

按照上面分析的思路写代码。先写桌子类,代码如下

public class Desk {private List<String> list = new ArrayList<>();// 放1个包子的方法// 厨师1 厨师2 厨师3public synchronized void put() {try {String name = Thread.currentThread().getName();// 判断是否有包子。if(list.size() == 0){list.add(name + "做的肉包子");System.out.println(name + "做了一个肉包子~~");Thread.sleep(2000);// 唤醒别人, 等待自己this.notifyAll();this.wait();}else {// 有包子了,不做了。// 唤醒别人, 等待自己this.notifyAll();this.wait();}} catch (Exception e) {e.printStackTrace();}}// 吃货1 吃货2public synchronized void get() {try {String name = Thread.currentThread().getName();if(list.size() == 1){// 有包子,吃了System.out.println(name  + "吃了:" + list.get(0));list.clear();Thread.sleep(1000);this.notifyAll();this.wait();}else {// 没有包子this.notifyAll();this.wait();}} catch (Exception e) {e.printStackTrace();}}
}

在这里插入图片描述

只有拿锁对象调用上述方法才不会出Bug,否则一定会出问题,因为只有锁对象知道当前谁占据了它,然后谁需要等待,所以锁对象调用wait()方法就会把占据它的方法进行等待,锁对象调notify()方法就会把等待锁对象的那些方法唤醒

再写测试类,在测试类中,创建3个厨师线程对象,再创建2个顾客对象,并启动所有线程

public class ThreadTest {public static void main(String[] args) {//   需求:3个生产者线程,负责生产包子,每个线程每次只能生产1个包子放在桌子上//      2个消费者线程负责吃包子,每人每次只能从桌子上拿1个包子吃。Desk desk  = new Desk();// 创建3个生产者线程(3个厨师)new Thread(() -> {while (true) {desk.put();}}, "厨师1").start();new Thread(() -> {while (true) {desk.put();}}, "厨师2").start();new Thread(() -> {while (true) {desk.put();}}, "厨师3").start();// 创建2个消费者线程(2个吃货)new Thread(() -> {while (true) {desk.get();}}, "吃货1").start();new Thread(() -> {while (true) {desk.get();}}, "吃货2").start();}
}

执行上面代码,运行结果如下:你会发现多个线程相互协调执行,避免无效的资源挣抢。

厨师1做了一个肉包子~~
吃货2吃了:厨师1做的肉包子
厨师3做了一个肉包子~~
吃货2吃了:厨师3做的肉包子
厨师1做了一个肉包子~~
吃货1吃了:厨师1做的肉包子
厨师2做了一个肉包子~~
吃货2吃了:厨师2做的肉包子
厨师3做了一个肉包子~~
吃货1吃了:厨师3做的肉包子
......

相关文章:

  • VCG 网格面片法向量平滑
  • Android Compose——ScrollableTabRow和LazyColumn同步滑动
  • Danswer部署指南
  • 计算机体系结构----缓存一致性/多处理机
  • OceanBase与MySQL兼容性对比
  • Python系列(1):简洁优雅,功能强大的编程语言
  • 《SRE Google 运维解密》笔记
  • 【Spring Cloud】Sentinel流量限流和熔断降级的讲解
  • 机器学习 -- 贝叶斯决策理论
  • 绘制几何图形(Shape)
  • ChatGpt使用技巧
  • x-cmd pkg | csview - 美观且高性能的 csv 数据查看工具
  • 31 树的存储结构二
  • 0基础学习VR全景平台篇第137篇:720VR全景,DJI无人机遥控器调参
  • 深入了解pnpm:一种高效的包管理工具
  • 【前端学习】-粗谈选择器
  • 3.7、@ResponseBody 和 @RestController
  • Consul Config 使用Git做版本控制的实现
  • iOS帅气加载动画、通知视图、红包助手、引导页、导航栏、朋友圈、小游戏等效果源码...
  • Linux CTF 逆向入门
  • mysql 5.6 原生Online DDL解析
  • Phpstorm怎样批量删除空行?
  • vue中实现单选
  • XForms - 更强大的Form
  • 从0实现一个tiny react(三)生命周期
  • 给Prometheus造假数据的方法
  • 海量大数据大屏分析展示一步到位:DataWorks数据服务+MaxCompute Lightning对接DataV最佳实践...
  • 精益 React 学习指南 (Lean React)- 1.5 React 与 DOM
  • 漫谈开发设计中的一些“原则”及“设计哲学”
  • 前端每日实战:61# 视频演示如何用纯 CSS 创作一只咖啡壶
  • 什么软件可以提取视频中的音频制作成手机铃声
  • 数据仓库的几种建模方法
  • 微服务框架lagom
  • 为物联网而生:高性能时间序列数据库HiTSDB商业化首发!
  • 函数计算新功能-----支持C#函数
  • 智能情侣枕Pillow Talk,倾听彼此的心跳
  • ​​快速排序(四)——挖坑法,前后指针法与非递归
  • ​LeetCode解法汇总2304. 网格中的最小路径代价
  • $.ajax()
  • (20)目标检测算法之YOLOv5计算预选框、详解anchor计算
  • (39)STM32——FLASH闪存
  • (delphi11最新学习资料) Object Pascal 学习笔记---第8章第2节(共同的基类)
  • (Ruby)Ubuntu12.04安装Rails环境
  • (solr系列:一)使用tomcat部署solr服务
  • (zz)子曾经曰过:先有司,赦小过,举贤才
  • (二)丶RabbitMQ的六大核心
  • (南京观海微电子)——COF介绍
  • (四)搭建容器云管理平台笔记—安装ETCD(不使用证书)
  • (一)spring cloud微服务分布式云架构 - Spring Cloud简介
  • (转)原始图像数据和PDF中的图像数据
  • .net下简单快捷的数值高低位切换
  • /bin、/sbin、/usr/bin、/usr/sbin
  • @DataRedisTest测试redis从未如此丝滑
  • @JSONField或@JsonProperty注解使用
  • @Transactional 详解