Java多线程设计模式之保护性暂挂模式

模式简介

多线程编程中,为了提高并发性,往往将一个任务分解为不同的部分。将其交由不同的线程来执行。这些线程间相互协作时,仍然可能会出现一个线程等待另一个线程完成一定的操作,其自身才能继续运行的情形。

保护性暂挂模式(Guarded Suspension)可以帮助我们解决上述的等待问题。该模式的核心思想是如果某个线程执行特定的操作前需要满足一定的条件,则在该条件未满足时将该线程暂停运行(即暂挂线程,使其处于waiting状态,直到该条件满足时才继续运行)。wait/notify可以用来实现保护性暂挂模式,但是,该模式还要解决wait/notify所解决的问题之外的问题。

模式架构

保护性暂挂模式的 核心是一个受保护的方法,该方法执行其所要真正执行的操作时需要满足特定的条件(Predicate),当条件不满足时,执行受保护方法的线程会被挂起进入等待状态,直到该条件满足时线程才会继续运行。 其类图如下所示:

在这里插入图片描述

  1. GuardedObject:包含受保护方法的对象,其主要方法及职责如下:

    • guardedMethod:受保护方法
    • stateChanged:改变GuardedObject实例状态的方法,该方法负责在保护条件成立时唤醒受保护方法的执行线程。
  2. GuardedAction:抽象了目标动作(受保护方法所要执行的操作),关联了目标动作所需的保护条件。其主要方法及职责如下

    • call:用户表示目标动作的方法
  3. ConcreteGuardedAction:应用程序所实现的具体目标动作极其关联的保护条件。

  4. Predicate:抽象了保护条件

    • evaluate:用于表示保护条件的方法
  5. ConcretePredicate:应用程序所实现的具体保护条件。

  6. Blocker:负责对执行guardedMethod的线程进行挂起和唤醒,并执行ConcreteGuardedAction所实现的目标操作,其方法及职责如下:

    • callWithGuard :负责执行目标操作和暂挂当前线程。
    • signalAfter:负责执行其参数指定的动作和唤醒由该方法所属Blocker实例所暂挂的线程中的一个线程。
    • signal:负责唤醒由该方法所述Blocker实例所暂挂的线程中一个线程。
    • broadcastAfter:负责执行其参数指定的动作和唤醒由该方法所属Blocker实例所暂挂的所有线程。
    • broadcast:负责唤醒由该方法所属Blocker实例暂挂的所有线程。
  7. ConditionVarBlocker:基于Java条件变量(java.util.concurrent.locks.Condition)实现的Blocker。

    其时序图如下
    在这里插入图片描述

    1. 客户端代码调用受保护方法guardedMethod。
    1. guardedMethod方法创建guardedAction实例
    1. guardedMethod 方法以guardedAction为参数调用Blocker实例的callWithGuard方法。
  • 4-5. callWithGuard方法调用guardedAction的getGuard方法获取保护条件Predicate。
  • 6-8. 循环判断保护条件是否成立,若保护条件成立,则循环退出。否则,循环将当前线程暂挂使其处于等待状态。当其他线程唤醒被暂挂的线程后,该循环仍然继续检测保护条件,并重复上述逻辑。
  • 9-10.callWithGuard方法调用guardedAction的call方法来执行目标动作,并记录call方法的返回值。
    1. callWithGuard将返回值返回给调用方。
    1. guardedMethod方法返回。

代码示例:

  1. GuardedObject中的guardedMethod方法。
    // 1. sendAlarm是一个受保护方法public void sendAlarm(final AlarmInfo alarm) throws Exception {// 2. 创建guardedAction实例GuardedAction<Void> guardedAction =new GuardedAction<Void>(agentConnected) {public Void call() throws Exception {doSendAlarm(alarm);return null;}};//  3. 调用Blocker实例的callWithGuard方法。blocker.callWithGuard(guardedAction);}
  1. blocker实例中的callWithGuard方法
public <V> V callWithGuard(GuardedAction<V> guardedAction) throws Exception {lock.lockInterruptibly();V result;try {//  4-5. callWithGuard方法调用guardedAction的getGuard方法获取保护条件Predicate。final Predicate guard = guardedAction.guard;while (!guard.evaluate()) {//6-8:循环判断保护条件是否成立Debug.info("waiting...");condition.await();}// 9-10 callWithGuard方法调用guardedAction的call方法来执行目标动作,并记录call方法的返回值。result = guardedAction.call();return result;} finally {lock.unlock();}}

受保护方法的执行线程被暂挂后,当保护条件成立时,其他线程需要唤醒该线程.其序列图如下

在这里插入图片描述

    1. 客户端代码调用stateChanged方法改变GuardedObject实例状态,这些状态包含了保护条件所关心的状态。
    1. stateChanged方法创建java.util.concurrent.Callable实例stateOperation,stateOperation封装了改变GuardedObject实例状态所需的操作。
    1. stateChanged方法以stateOperation为参数,调用Blocker实例的signalAfter方法。
  • 4-5 signalAfter方法调用stateOperation对象的call方法以改变GuardedObject实例的状态,并记录其返回值shouldSignalBlocker
  • 6-7. signalAfter方法在shouldSignalBlocker值为true时,调用java.util.concurrent.locks.Condition实例的signal方法唤醒被该Condition实例所暂挂的线程中的一个线程。
    1. signalAfter方法返回,此时,执行受保护方法的线程可能已经被唤醒(取决于shouldSignalBlocker值是否为true)。

代码示例:

    protected void onConnected() {try {//2-3.创建stateOperation,调用Blocker实例的signalAfter方法blocker.signalAfter(new Callable<Boolean>() {@Overridepublic Boolean call() {connectedToServer = true;Debug.info("connected to server");return Boolean.TRUE;}});} catch (Exception e) {e.printStackTrace();}}public void signalAfter(Callable<Boolean> stateOperation) throws Exception {lock.lockInterruptibly();try {//4-5 signalAfter方法调用stateOperation对象的call方法以改变GuardedObject实例的状态if (stateOperation.call()) {//调用java.util.concurrent.locks.Condition实例的signal方法唤醒被该Condition实例所暂挂的线程中的一个线程。condition.signal();}} finally {lock.unlock();}}

模式的评价与实现考量

关注点分离,保护性暂挂模式中的各个参与者各自仅关注本模式所要解决的问题中的一个方面,各个参与者的职责是高度内聚的。这使得保护性暂挂模式便于理解和应用,应用开发人员只需要根据应用的需要实现GuardedObject、ConcretePredicate、和ConcreteGuardedAction这几个必须由应用实现的参与者即可,而其他参与者的实现都是可复用的。

可能增加JVM垃圾回收的负担,为了使GuardedAction实例的call方法能够访问保护方法guardedMethod参数,我们需要利用闭包。因此,GuardedAction实例可能是在保护方法中创建的,这意味着,每次保护方法被调用的时候都会有个新的GuardedAction实例被创建。而这会增加JVM内存池的占用,从而增加垃圾回收的负担。

可能增加上下文切换,这点与保护性暂挂模式本身无关。只不过,不管如何实现该模式,只要这里面涉及线程的暂挂和唤醒就会引起上下文切换。如果频繁出现保护方法被调用时保护条件不成立,那么保护方法的执行线程就会频繁的被暂挂和唤醒,从而导致频繁的上下文切换。

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

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

相关文章

Android Room数据库使用介绍

1.简介 Room是Google提供的Android架构组件之一&#xff0c;旨在简化数据库操作。它是SQLite的一个抽象层&#xff0c;提供了更易用和安全的API。 Room的总体架构: 2.Room数据库的基础概念 Entity Entity是Room中的数据表&#xff0c;每个Entity类对应一个SQLite表。 DAO …

研发团队的「技术债」如何进行量化管理?

我共事过的每个团队都会讨论技术债。有些团队知道如何管理它&#xff0c;也有些团队因此崩溃瘫痪&#xff0c;甚至有一家公司因为技术债务没有得到解决而宣告失败。 什么是技术债务&#xff1f; 「债务」这个比喻非常恰当。最早提出「技术债务 Technical Debt」比喻的工程师 W…

Linux(Centos7)OpenSSH漏洞修复,升级最新openssh-9.7p1

OpenSSH更新 一、OpenSSH漏洞二、安装zlib三、安装OpenSSL四、安装OpenSSH 一、OpenSSH漏洞 服务器被扫描出了漏洞需要修复&#xff0c;准备升级为最新openssh服务 1. 使用ssh -v查看本机ssh服务版本号 ssh -V虚拟机为OpenSSH7.4p1&#xff0c;现在准备升级为OpenSSH9.7p1…

Centos7 安装oracle 11.2.0.4

荆轲刺秦王 1. 准备工作 需要下载 Oracle 11g 安装包 2.HostName修改&#xff1a; hostnamectl set-hostname oracle 3. 配置hostname&#xff08;本机IP映射&#xff09;注意&#xff1a;192.168.116.129 需要换乘本地ip vi /etc/hosts 192.168.116.129 oracle # 测试hos…

创新实训2024.06.17日志:大模型微调总结

前段时间其实我们已经部署了大模型&#xff0c;并开放了对外的web接口。不过由于之前某几轮微调实验的大模型在对话时会有异常表现&#xff08;例如响应难以被理解&#xff09;&#xff0c;因此我在项目上线后&#xff0c;监控了数据库里存储的对话记录。确定了最近一段时间部署…

基 CanMV 的 C 开发环境搭建

不论是使用 CanMV 提供的基于 C 语言和 FreeRTOS 的应用开发方式开发应用程序或是编译 CanMV 固件&#xff0c;都需要搭建基于 CanMV 的 C 开发环境&#xff0c;用于编译 CanMV 源码。 1. 开发环境搭建说明 CanMV 提供了基于 C 语言和 FreeRTOS 的应用开发…

【教程】hexo 更换主题后,部署在 Github Page 无 CSS 样式

目录 前言环境hexo 更换主题解决部署到 Github Page 后无 CSS 样式的问题 前言 最近更换了 hexo 的主题后&#xff0c;重新部署到 Github Page 上发现不显示 CSS 样式&#xff0c;但在本地启动时又是正常的效果。此外&#xff0c;检查资源请求&#xff0c;发现多个 .css 文件请…

【软件测试】软件测试入门

软件测试入门 一、什么是软件测试二、软件测试和软件开发的区别三、软件测试在不同类型公司的定位1. 无组织性2. 专职 OR 兼职3. 项目性VS.职能性4.综合型 四、一个优秀的软件测试人员具备的素质1. 技能相关2. 非技能相关 一、什么是软件测试 最常见的理解是&#xff1a;软件测…

【效率提升】倍速插件Global Speed

global speed插件可以控制网页在线视频&#xff0c;能够应用在Edge和Google浏览器中&#xff0c;只需要在插件商店中下载并配置即可。这款插件的配置选项有很多&#xff0c;支持视频倍速&#xff08;最低0.25倍速&#xff0c;最高16倍速&#xff09;&#xff0c;固定标签页&…

【Java开发规范】IDEA 设置 text file encoding 为 UTF-8,且文件的换行符使用 Unix 格式

1. IDEA 设置 text file encoding 为 UTF-8 file -> settings -> editor -> code style -> file encoding Transparent-native-to-asci conversion 要不要勾选&#xff1f;> 不推荐勾选&#xff08;它的作用是用来自动转换ASCII编码&#xff0c;防止文件乱码&am…

Modbus协议转Profibus协议模块接热传感器配置攻略

一、前言 在工业自动化控制领域&#xff0c;Modbus协议和Profibus协议是两种常见的通讯协议&#xff0c;它们在设备之间传输数据起着至关重要的作用。而Modbus协议转Profibus协议模块&#xff08;XD-MDPB100&#xff09;设备&#xff0c;则扮演着连接不同通讯协议的桥梁角色。…

来点干货,比较好用的3D在线展示网站

制作好的3D模型需要客户对3D模型进行确认&#xff0c;图片和视频给过去&#xff0c;后面往往都会扯皮。无意间翻到几个3D展示网站&#xff0c;试用了下都不是很完善&#xff0c;后面在网上大量查阅资料并经过实际使用&#xff0c;发现几个相对比较好用值得推荐的。 1、Sketchf…

Python 数据持久化:使用 SQLite3 进行简单而强大的数据存储

&#x1f340; 前言 博客地址&#xff1a; CSDN&#xff1a;https://blog.csdn.net/powerbiubiu &#x1f44b; 简介 SQLite3是一种轻量级嵌入式数据库引擎&#xff0c;它在Python中被广泛使用。SQLite3通常已经包含在Python标准库中&#xff0c;无需额外安装。你只需导入 s…

IRIS论文阅读笔记

这是ICLR2023一篇world model的论文&#xff0c;提出了一个称为IRIS的world model方法模型仍然是分为两部分&#xff0c;一部分是模拟世界的world model&#xff0c;包括预测下一帧的观测&#xff0c;预测当前reward&#xff0c;预测是否terminate的三个输出&#xff1b;第二部…

Linux ubuntu安装pl2303USB转串口驱动

文章目录 1.绿联PL2303串口驱动下载2.驱动安装3.验证方法 1.绿联PL2303串口驱动下载 下载地址&#xff1a;https://www.lulian.cn/download/16-cn.html 也可以直接通过CSDN下载&#xff1a;https://download.csdn.net/download/Axugo/89447539 2.驱动安装 下载后解压找到Lin…

【Linux命令行】从时间管理->文件查找压缩的指令详解

目录 1.date 命令&#xff08;显示时间&#xff09; 1.1 显示方面 1.2 设定时间 1.3 时间戳转换 1.4 cal&#xff08;日历&#xff09; 2. 重定向 2.1 输出重定向&#xff08;echo >&#xff09;cin 2.2 追加重定向 >> 2.3 输入重定向 < cout 3.find 指…

API接口设计的艺术:如何提升用户体验和系统性能

在数字时代&#xff0c;API接口的设计对于用户体验和系统性能有着至关重要的影响。良好的设计可以显著提升应用程序的响应速度、可靠性和易用性。以下是几个关键点&#xff0c;帮助改善API接口的设计&#xff1a; 1. 理解并定义清晰的要求 用户研究&#xff1a;与最终用户进行…

如何根据使用场景选购3D扫描仪?

三维扫描建模是指通过专业的三维扫描仪对产品进行三维数据的采集&#xff0c;快速获取物体精确的3D数据&#xff0c;实现1:1复刻原物体&#xff0c;扫描后所得的数字化3D模型以obj、fbx、glb、gltf等格式保存。 积木易搭自主研发多款三维扫描设备&#xff0c;拥有多项国家专利&…

【大分享04】OFD版式赋能政务服务电子文件归档和电子档案管理

关注我们 - 数字罗塞塔计划 - 本篇是参加由电子文件管理推进联盟联合数字罗塞塔计划发起的“大分享”活动投稿文章&#xff0c;来自北京数科网维技术有限责任公司&#xff0c;作者&#xff1a;张严。 PART1 政务服务电子文件归档和电子档案管理背景 政务服务是政务服务机构…

RockChip Android12 Settings一级菜单

一:概述 在之前的文章中对Android8.1 Settings的流程进行了说明,本章将针对Android12 Settings一级菜单的加载逻辑进行详细说明,Settings版本之间的差异不是很大,有兴趣的同学可自行学习,本文不在做赘述。 Android8.1 Settings说明:RockChip Android8.1 Settings-CSDN博…