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

同步模式之保护性暂停

同步模式之保护性暂停

定义

Guarded Suspension,用在一个线程等待另一个线程的执行结果

要点

· 有一个结果需要从一个线程传递到另一个线程,让它们关联同一个GuardedObject

· 如果有结果不断从一个线程到另一个线程那么可以使用消息队列

· JDK中,join的实现、Future的实现,采用的就是此模式

· 因为要等待另一方结果,因此归类到同步模式

在这里插入图片描述

实现

@Slf4j(topic = "c.GuardedObject")
public class GuardedObject {//线程1等待线程2的下载结果public static void main(String[] args) {MyTest myTest = new MyTest();new Thread(()->{//等待结果log.debug("等待结果");Object res = (Date)myTest.get();log.debug("结果是:{}",res);},"t1").start();new Thread(()->{log.debug("执行下载");try {Thread.sleep(10000);myTest.complete(new Date());} catch (InterruptedException e) {e.printStackTrace();}},"t2").start();}}class MyTest{// 结果private Object response;//获取结果的方法public Object get(){synchronized (this){while (response == null){try {this.wait();} catch (InterruptedException e) {e.printStackTrace();}}return response;}}//产生结果public void complete(Object response){synchronized (this){//给结果成员变量赋值this.response = response;this.notifyAll();}}
}

优点

相较于join来说,join只能等另一个线程结束,而这种模式在唤醒等待线程后还可以让当前线程继续执行别的代码。而且使用join时,等待结果的变量只能设计成全局的,而这种设计方法可以将变量设置成局部的。

扩展1-增加超时效果

@Slf4j(topic = "c.GuardedObject")
public class GuardedObject {//线程1等待线程2的下载结果public static void main(String[] args) {MyTest myTest = new MyTest();new Thread(()->{//等待结果log.debug("等待结果");Object res = (Date)myTest.get(5000);log.debug("结果是:{}",res);},"t1").start();new Thread(()->{log.debug("执行下载");try {Thread.sleep(10000);myTest.complete(new Date());} catch (InterruptedException e) {e.printStackTrace();}},"t2").start();}}class MyTest{// 结果private Object response;//获取结果的方法public Object get(long timeout){synchronized (this){//开始时间long begin = System.currentTimeMillis();//经历的时间long passedTime = 0;while (response == null){//等待时间long waitTime = timeout-passedTime;if(waitTime<=0){break;}//经历的时间超过了最大等待时间,退出循环if(passedTime >= timeout){break;}try {//避免虚假唤醒使再次等待的时间变长this.wait(waitTime);} catch (InterruptedException e) {e.printStackTrace();}//求得经历时间passedTime = System.currentTimeMillis() - begin;}return response;}}//产生结果public void complete(Object response){synchronized (this){//给结果成员变量赋值this.response = response;this.notifyAll();}}
}

join原理

join底层采用了保护性暂停模式

在这里插入图片描述

扩展2

在这里插入图片描述

图中Futures就好比居民楼一层的信箱(每个信箱有房间编号),左侧的t0,t2,t4就好比等待邮件的居民,右侧的t1,t3,t5就好比邮递员

如果需要在多个类之间使用GuardedObject对象,作为参数传递不是很方便,因此设计一个用来解耦的中间类,这样不仅能够解耦结果等待者和结果生产者,还能够同时支持多个任务的管理

实现代码

@Slf4j(topic = "c.GuardedObject")
public class GuardedObject {public static void main(String[] args) throws InterruptedException {for (int i = 0; i < 3; i++) {new People().start();}Thread.sleep(1000);for (Integer id : Mailboxes.getIds()) {new Postman(id,"内容"+id).start();}}
}@Slf4j(topic = "c.People")
class People extends Thread{@Overridepublic void run() {// 收信MyTest guardedObject = Mailboxes.createGuardedObject();log.debug("开始收信 id:{}",guardedObject.getId());Object mail = guardedObject.get(5000);log.debug("收到信 id:{},内容:{}",guardedObject.getId(),mail);}
}@Slf4j(topic = "c.Postman")
class Postman extends Thread{private int id;private String mail;public Postman(int id,String mail){this.id = id;this.mail = mail;}@Overridepublic void run() {MyTest guardedObject = Mailboxes.getGuardedObject(id);log.debug("开始送信 id:{},内容{}",id,mail);guardedObject.complete(mail);}
}class Mailboxes{private static Map<Integer,MyTest> boxes = new Hashtable<>();private static int id = 1;//产生唯一idprivate static synchronized int generateId(){return id++;}public static MyTest getGuardedObject(int id){return boxes.remove(id);}public static MyTest createGuardedObject(){MyTest go = new MyTest(generateId());boxes.put(go.getId(),go);return go;}public static Set<Integer> getIds(){return boxes.keySet();}
}class MyTest{// 标识 Guarded Objectprivate int id;public MyTest(int id) {this.id = id;}public int getId() {return id;}// 结果private Object response;//获取结果的方法public Object get(long timeout){synchronized (this){//开始时间long begin = System.currentTimeMillis();//经历的时间long passedTime = 0;while (response == null){//等待时间long waitTime = timeout-passedTime;if(waitTime<=0){break;}//经历的时间超过了最大等待时间,退出循环if(passedTime >= timeout){break;}try {//避免虚假唤醒使再次等待的时间变长this.wait(waitTime);} catch (InterruptedException e) {e.printStackTrace();}//求得经历时间passedTime = System.currentTimeMillis() - begin;}return response;}}//产生结果public void complete(Object response){synchronized (this){//给结果成员变量赋值this.response = response;this.notifyAll();}}
}

http://www.mrgr.cn/news/62548.html

相关文章:

  • MacOS的powermetrics命令查看macbook笔记本的耗能情况,附带查看ANE的工作情况
  • 《C++性能秘籍:巧用 CPU 缓存优化数据访问》
  • 代码随想录第十五天
  • 栈和队列(下)-队列
  • 拓展学习-golang的基础语法和常用开发工具
  • 【Python各个击破】matplotlib
  • 声屏障结构设计福音!基于伏图的声屏障结构强度校核仿真APP开发及应用
  • 阿里云物联网的通信方式
  • 尚航科技亮相中国国际数字经济博览会,重磅发布怀来尚云智算中心
  • Centos环境下安装docker
  • 国标GB28181设备管理软件EasyGBS国标GB28181公网平台应用到“雪亮工程”
  • 开放式耳机哪个品牌好用值得选择?2024开放式耳机蓝牙排行榜
  • 计算机毕业设计django+大模型租房推荐系统 租房可视化 租房大屏可视化 租房爬虫 spark 58同城租房爬虫 房源推荐系统
  • 【ChatGPT】搜索趋势分析
  • Spring Boot在校园社团信息管理中的实践与思考
  • 北京神州分诊叫号系统 doctor 任意文件上传漏洞
  • 最新AI绘画ComfyUI整合包又更新了!
  • 【天线&空中农业】蜜蜂检测系统源码&数据集全套:改进yolo11-ASF
  • go-logger v0.27.0 - 并发性能为官方库 10 倍
  • echarts 实现3D饼状图 加 label标签显示
  • 编程知识概览
  • C#核心(5)构造,析构,垃圾回收
  • 一文说清什么是数据要素
  • 如何使用weditor定位iphone手机的控件?
  • 基于Openwrt系统架构,实现应用与驱动的实例。
  • SpringBoot旋律线:Web音乐网站构建