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

一个方法被多个线程同时调用,确保同样参数的调用只能有一个线程执行,不同参数的调用则可以多个线程同时执行

我们知道通过lock一个固定静态object给代码段加同步锁,可以让多个线程的同时调用以同步执行,因此可以利用字典来给不同参数分配不同的静态对象,方法中不同的参数调用锁住各自不同的静态对象即可实现不同参数不加锁,相同参数才加锁的需求,而多线程更新操作的字典需要用到线程安全的ConcurrentDictionary防止争用,因此这里的静态加锁对象字典类型为ConcurrentDictionary<string, object>。

比如场景:在数据库某表没有唯一约束的情况下,有可能前端请求和程序定时服务同时执行写入操作,这时写入操作在不同的线程中执行,虽然写入之前作了判断记录是否已存在的操作,但可能两个线程同时执行都判断了记录不存在,因此都执行了写入操作,就造成了记录重复的可能。

写一个调用管理类“MultiInvokeManager”,通过该类来控制这种相同参数同时调用的可能性

/// <summary>
/// 多线程调用方法控制类
/// </summary>
public static class MultiInvokeManager
{//参数调用匹配加锁对象字典private static readonly ConcurrentDictionary<string, object> _lockMap = new ConcurrentDictionary<string, object>();           /// <summary>/// 根据调用参数(比如方法参数中唯一的订单号)对应的“key”,排除相同参数的“action”操作同时被执行/// </summary>/// <param name="key">相同参数匹配相同的key(比如唯一的订单号),以便相同参数不可同时调用</param>/// <param name="action">通过key是否相同决定是否需要限制同步执行的操作</param>public static void SyncInvokeForSameArgs(string key, Action action){object obj = _lockMap.GetOrAdd(key, new object());lock (obj){action();}}/// <summary>/// 控制的操作执行后,在适当的时机调用该方法释放字典中的对象,以便垃圾回收,防止累积占用内存/// </summary>/// <param name="key"></param>public static void ReleaseLockObject(string key){_lockMap.TryRemove(key, out _);}
}

1. 程序定时服务中调用:

MultiInvokeManager.SyncInvokeForSameArgs(tradeNo, () =>UpdateUserMemberStatus(userId, tradeNo, transactionId, payAmount).Wait()
);
MultiInvokeManager.ReleaseLockObject(tradeNo);

2. 前端请求方法中调用:

MultiInvokeManager.SyncInvokeForSameArgs(tradeNo, () =>UpdateMemberStatus(tradeNo, transactionId, payAmount).Wait()
);
MultiInvokeManager.ReleaseLockObject(tradeNo);

 以上两处调用中“UpdateUserMemberStatus”和“UpdateMemberStatus”方法,执行的都是判断“tradeNo”在原来某历史表中是否已经存在,不存在则Insert历史表并Update关联主表的相同操作,因此利用上面管理类“MultiInvokeManager”来控制防止相同参数的写入可能同时发生的可能(同时保持不同参数的写入依旧可以在不同线程中同时进行)

http://www.lryc.cn/news/522792.html

相关文章:

  • 3. MySQL事务并发的问题与解决方法
  • 25/1/15 嵌入式笔记 初学STM32F108
  • MySQL的不同SQL模式导致行为不同?
  • Flink 使用 Kafka 作为数据源时遇到了偏移量提交失败的问题
  • 【日志篇】(7.6) ❀ 01. 在macOS下刷新FortiAnalyzer固件 ❀ FortiAnalyzer 日志分析
  • LSA更新、撤销
  • DevUI 2024 年度运营报告:开源生态的成长足迹与未来蓝图
  • centos 7 Mysql服务
  • React 表单处理与网络请求封装详解[特殊字符][特殊字符]
  • C++ 的 CTAD 与推断指示(Deduction Guides)
  • 【Rust自学】13.2. 闭包 Pt.2:闭包的类型推断和标注
  • 如何将原来使用cmakelist编译的qt工程转换为可使用Visual Studio编译的项目
  • 微软确认Win10停更不碍Microsoft 365使用!未来是否更新成谜
  • Ubuntu、Windows系统网络设置(ping通内外网)
  • 华为OD机试E卷 ---最大值
  • UllnnovationHub,一个开源的WPF控件库
  • Fabric区块链网络搭建:保姆级图文详解
  • Kubernetes (K8s) 权限管理指南
  • IM聊天学习资源
  • 计算机视觉模型的未来:视觉语言模型
  • 【JAVA 基础 第(19)课】Hashtable 类用法和注意细节,是Map接口的实现类
  • 浅谈 JVM
  • html的iframe页面给帆软BI发送消息
  • spark任务优化参数整理
  • C++ 模拟真人鼠标轨迹算法 - 防止游戏检测
  • 生产环境中常用的设计模式
  • 基于SpringBoot+Vue的药品管理系统【源码+文档+部署讲解】
  • 【CompletableFuture实战】
  • Redis 缓存穿透、击穿、雪崩 的区别与解决方案
  • Python自动化测试中定位隐藏菜单元素的策略