Skip to main content
 首页 » 编程设计

c#之锁字典不断增长,不知如何清理

2024年02月23日28lyj

我有一个基于 Web 的商品订购系统。

  • 商品限时,售卖 Y 小时
  • 每件商品只允许 X 个订单

为了保持每件商品的订单 <= X,我使用了这种锁定机制。

private static Dictionary<Guid, Object> PurchaseLockDictionary = null; 
 
private static object GetLock(Guid itemId) 
    { 
        if (!PurchaseLockDictionary.ContainsKey(itemId)) 
        { 
            PurchaseLockDictionary.Add(itemId, new object()); 
        } 
        return PurchaseLockDictionary[itemId]; 
    } 

购买看起来像这样:

public static Order Purchase(Buyer buyer, OrderItem item) 
    { 
        Order order; 
        try 
        { 
            lock (GetLock(item.Id)) 
            { 
                // order stuff like counting current amount of orders, buyer validity etc 
            } 
        } catch (Exception e) { 
            // Exception stuff 
        } 
        return order; 
    } 

现在,我的问题是,如何防止锁定机制(Dictionary 对象)超出比例?目前我们出于其他原因每周重新启动一次服务器,但我不希望代码依赖于这种行为。

是否有另一种数据结构更适合这种锁机制?或者是否有一种聪明的方法来查找和清理词典中的旧条目?非常欢迎提出想法!

请您参考如下方法:

using (var locker = new PurchaseLocker(item.Id)) 
{ 
    // order stuff like counting current amount of orders, buyer validity etc 
} 
 
// ... 
 
public sealed class PurchaseLocker : IDisposable 
{ 
    private static readonly object _bigLock = new object(); 
    private static readonly Dictionary<Guid, LockToken> _lockMap = new Dictionary<Guid, LockToken>(); 
    private readonly Guid _itemId; 
 
    public PurchaseLocker(Guid itemId) 
    { 
        _itemId = itemId; 
 
        LockToken miniLock; 
        lock (_bigLock) 
        { 
            if (!_lockMap.TryGetValue(itemId, out miniLock)) 
            { 
                miniLock = new LockToken(); 
                _lockMap.Add(itemId, miniLock); 
            } 
            miniLock.Count++; 
        } 
        Monitor.Enter(miniLock); 
    } 
 
    public void Dispose() 
    { 
        lock (_bigLock) 
        { 
            LockToken miniLock = _lockMap[_itemId]; 
            miniLock.Count--; 
            if (miniLock.Count == 0) 
                _lockMap.Remove(_itemId); 
 
            Monitor.Exit(miniLock); 
        } 
    } 
 
    private sealed class LockToken 
    { 
        public int Count; 
    } 
}