我锁定队列是否很重要?
public abstract class ExpiringCache<TKey,TValue> : IDisposable
{
protected readonly object locker = new object();
protected readonly Dictionary<TKey, TValue> cache =
new Dictionary<TKey, TValue>();
private readonly Queue<KeyValuePair<TKey, long>> queue =
new Queue<KeyValuePair<TKey, long>>();
private volatile bool dispose;
private readonly Thread cleaningThread;
private readonly long lifeSpanTicks;
public ExpiringCache(TimeSpan lifeSpan)
{
// Validate lifeSpan
if (lifeSpan.Ticks == 0)
{
throw new ArgumentOutOfRangeException
("lifeSpan", "Must be greater than zero.");
}
this.lifeSpanTicks = lifeSpan.Ticks;
// Begin expiring expired items
this.cleaningThread = new Thread(() =>
{
while (!this.dispose)
{
this.RemoveExpired();
Thread.Sleep(1);
}
});
this.cleaningThread.Start();
}
private void RemoveExpired()
{
if (this.queue.Count == 0)
{
return;
}
var pair = this.queue.Peek();
if (pair.Value >= DateTime.Now.Ticks)
{
lock (this.locker)
{
this.cache.Remove(pair.Key);
}
this.queue.Dequeue();
}
}
public bool Contains(TKey key)
{
lock (this.locker)
{
return this.cache.ContainsKey(key);
}
}
public void Add(TKey key, TValue value)
{
lock (this.locker)
{
this.cache.Add(key, value);
}
this.queue.Enqueue(new KeyValuePair<TKey, long>
(key, DateTime.Now.Ticks + this.lifeSpanTicks));
}
public void Dispose()
{
this.dispose = true;
}
}
答案 0 :(得分:5)
仅仅锁定Contains方法是不够的。看到这个:
http://blogs.msdn.com/jaredpar/archive/2009/02/16/a-more-usable-thread-safe-collection.aspx
基本上,您需要重新考虑经典的Queue API并使用DequeueIfContains()
之类的方法而不是简单的Contains()
+ Dequeue()
,这样同一个锁同时适用于{{ 1}}检查和Contains
操作。
答案 1 :(得分:0)
您可以使用:ConcurrentDictionary<TKey, TValue>
和ConcurrentQueue<T>
。它们内置于C#.Net 4.0及更高版本中。