对Monitor的使用可以防止lock的时间过长并且可以设置其对应的超时时间达到对预期代码的一个控制,合理的使用timeout可以有助于程序的健壮性。但是对于不同的并发程序可能某些时候我们需要的粒度是不一样的,从而产生的一个问题是需要更细粒度的锁来保证,又因为默认的字符串无法共享导致的无法通过string来进行锁粒度的细分所以可能需要自己重写一个锁来保证到达更细粒度的控制,可能这时候有人要说不是有string.Intern可以进行字符串保留,达到类似的效果,对于这个我只想说内部确定的字符串确实可以达到这个效果,但是因为字符串保留机制就导致了gc不会对此进行回收,会导致如果外部输入的string是不可控的情况下就可以给程序造成诸如oom的问题,对此我抛砖引玉希望各位博友可以提出宝贵的意见或者建议,或者有现成的更好的解决方案也请分享一下,下面贴代码:

    public class MonitorStr
{
private MonitorStr() { }
private static ConcurrentDictionary<string, MonitorStrEntry> _lockDics = new ConcurrentDictionary<string, MonitorStrEntry>();
private const int _concurrentCount = 31;
private static object[] _lockers = new object[_concurrentCount]; static MonitorStr()
{
for (int i = 0; i < _concurrentCount; i++)
{
_lockers[i] = new object();
}
}
private static int GetIndex(string key)
{
return Math.Abs(key.GetHashCode() % _concurrentCount);
}
public static bool TryEnter(string key, int timeoutMillis)
{
if (string.IsNullOrWhiteSpace(key))
throw new ArgumentNullException(nameof(key));
MonitorStrEntry entry = null;
var locker = _lockers[GetIndex(key)];
lock (locker)
{
if (!_lockDics.TryGetValue(key, out entry))
{
entry = new MonitorStrEntry();
_lockDics[key] = entry;
}
entry.Increment();
} var acquired = Monitor.TryEnter(entry, timeoutMillis);
if (!acquired)
entry.Decrement();
return acquired;
} public static void Exit(string key)
{
var entry = _lockDics[key];
Monitor.Exit(entry);
if (entry.Decrement() == 0)
{
var locker = _lockers[GetIndex(key)];
lock (locker)
{
if (entry.CanRemove())
{
Console.WriteLine(key + "remove");
_lockDics.TryRemove(key, out var v);
}
}
}
}
class MonitorStrEntry
{
private int _lockCount; public int Increment()
{
Interlocked.Increment(ref _lockCount);
return _lockCount;
} public int Decrement()
{
Interlocked.Decrement(ref _lockCount);
return _lockCount;
}
public bool CanRemove()
{
return _lockCount == 0;
}
} }

这个代码的原理就是利用数组对象锁和传入的string key进行对不同key之间的粒度的区分,因为不同的key之间的hashcode不一致所以对取到的锁对象locker也不一样,达到降低锁并发的级别,字典存储的entry内部维护一个锁的加锁次数达,利用cas保证并发多线程安全且高效。

如何使用

            var key = "testKey";
var timeoutMillis = 3000;
var acquired = false;
try
{ acquired = MonitorStr.TryEnter(key, timeoutMillis);
if (acquired)
{
//Do Something
}
else
{
throw new XXXTimeOutException();
}
}
finally
{
MonitorStr.Exit(key);
}

哪个场景下可以使用呢?

            //使用场景,诸如多线程查数据库环境的情况下
var userId = "xxxx";
var user = Cache.Query(userId);
if (user == null)
{
var acquired = false;
try
{ acquired = MonitorStr.TryEnter(key, timeoutMillis);
if (acquired)
{
//Do Something
user = Cache.Query(userId);
if (user == null)
{
user = DB.Query(userId);
}
}
else
{
throw new XXXTimeOutException();
}
}
finally
{
MonitorStr.Exit(key);
}
}

谢谢

Monitor的扩展支持string的超时锁的更多相关文章

  1. openerp学习笔记 domain 增加扩展支持,例如支持 <field name="domain">[('type','=','get_user_ht_type()')]</field>

    示例代码1,ir_action_window.read : # -*- coding: utf-8 -*-from openerp.osv import fields,osv class res_us ...

  2. 如何基于String实现同步锁?

    在某些时候,我们可能想基于字符串做一些事情,比如:针对同一用户的并发同步操作,使用锁字符串的方式实现比较合理.因为只有在相同字符串的情况下,并发操作才是不被允许的.而如果我们不分青红皂白直接全部加锁, ...

  3. wrk 及扩展支持 tcp 字节流协议压测

    wrk 及扩展支持 tcp 字节流协议压测 高性能.方便使用的 HTTP(s) 的流量压测工具,结合了多个开源项目开发而成: redis 的 ae 事件框架 luajit openssl http-p ...

  4. 如何基于 String 实现同步锁?

    如何基于String实现同步锁? 在某些时候,我们可能想基于字符串做一些事情,比如:针对同一用户的并发同步操作,使用锁字符串的方式实现比较合理. 因为只有在相同字符串的情况下,并发操作才是不被允许的. ...

  5. //四舍五入//得到倒序//比较字符串//拦截时间,实现超时锁屏//判断是否越狱//配置PodFile//Storyboard中跳转操作//处理不可逆的push界面操作

    //处理不可逆的push界面操作 VerifyRealNameViewController *verifyRealNameCtrl = [VerifyRealNameViewController vi ...

  6. ExtJs4 笔记(2) ExtJs对js基本语法扩展支持

    本篇主要介绍一下ExtJs对JS基本语法的扩展支持,包括动态加载.类的封装等. 一.动态引用加载 ExtJs有庞大的类型库,很多类可能在当前的页面根本不会用到,我们可以引入动态加载的概念来即用即取.这 ...

  7. 安装php的memcached模块和扩展支持sasl

    memcached的1.2.4及以上增加了CAS(Check and Set)协议,对于同一key的多进行程的并发处理问题.这种情况其实根数据库很像,如果同时有几个进程对同一个表的同一数据进行更新的话 ...

  8. ExtJs对js基本语法扩展支持

    ExtJs对js基本语法扩展支持 本篇主要介绍一下ExtJs对JS基本语法的扩展支持,包括动态加载.类的封装等. 一.动态引用加载 ExtJs有庞大的类型库,很多类可能在当前的页面根本不会用到,我们可 ...

  9. [转载]ExtJs4 笔记(2) ExtJs对js基本语法扩展支持

    作者:李盼(Lipan)出处:[Lipan] (http://www.cnblogs.com/lipan/) 本篇主要介绍一下ExtJs对JS基本语法的扩展支持,包括动态加载.类的封装等. 一.动态引 ...

随机推荐

  1. 每天一个linux命令:ps命令

      Linux中的ps命令是Process Status的缩写.ps命令用来列出系统中当前运行的那些进程.ps命令列出的是当前那些进程的快照,就是执行ps命令的那个时刻的那些进程,如果想要动态的显示进 ...

  2. .Net Core 3.0 MVC 中使用 SqlSugar ORM框架

    介绍 SqlSugar 是一款简单易用的ORM ,在国内市场占有率也比较高, 在今年10月份官网改版后  提供了完整的服务,让您的项目没有后顾之忧 下载地址 :https://github.com/s ...

  3. Ⅱ Finite Markov Decision Processes

    Dictum:  Is the true wisdom fortitude ambition. -- Napoleon 马尔可夫决策过程(Markov Decision Processes, MDPs ...

  4. origin把点图和线图放在一起

    首先分别做好点图和线图在两个graph中,然后选中其中一副图(点图或者线图),然后按下图选择: 如果有多个图,可以在弹出窗口中选择多个sheet.

  5. dubbo,hessian过滤器filter使用

    Dubbo的Filter在使用的过程中是我们扩展最频繁的内容,而且Dubbo的很多特性实现也都离不开Filter的工作,今天一起来看一下Filter的具体实现. Filter(过滤器)在很多框架中都有 ...

  6. 蒲公英 · JELLY技术周刊 Vol 27: 平平无奇 React 17

    蒲公英 · JELLY技术周刊 Vol.27 这个热闹的十月终于要走到尾声,React 17 历经 4 个 RC 版本之后,也于数天前正式发布了,而同在几天前发布的 CRA 4.0 也已经完成了 Re ...

  7. localStorage 用法

    localStorage使用总结   一.什么是localStorage.sessionStorage 在HTML5中,新加入了一个localStorage特性,这个特性主要是用来作为本地存储来使用的 ...

  8. 通过Python提取10000份log中的产品数据

    一.背景 协助产品部门在10000份产品log信息中提取产品的SN号.IMEI号.ICCID号到Excel表格中. 1.l原始的og内容: 2.提取后的Excel表格: 二.实现 1.思路 a.for ...

  9. 【算法】HashMap相关要点记录

    在刷leetcode的算法题时,HashMap需要大量使用,而且也是面试的高频问题.这里记录了HashMap一些增.删.改.查的实现细节和时间复杂度,罗列了一些比较有用的方法,以及其它的一些细节. 1 ...

  10. Yii2使用数据库操作汇总(增删查改、事务)

    查询 //1.简单查询 $admin=Admin::model()->findAll($condition,$params); $admin=Admin::model()->findAll ...