实现线程安全的Dictionary<TKey, TValue>
1. 不安全的泛型集合Dictionary<TKey, TValue>
泛型集合Dictionary<TKey, TValue>不是线程安全的。在多线程环境下读写Dictionary<TKey, TValue>,程序经常抛出异常。下面程序中,启动两个线程,遍历集合(读操作);启动一个线程,每秒向集合中添加一个项。
using System;
using System.Collections.Generic;
using System.Threading;
namespace DictionaryTest
{
class User
{
public string Name { get; set; }
public string Password { get; set; }
public DateTime OnlineTime { get; set; }
public bool IsAdministrator { get; set; }
}
class Program
{
static Dictionary<string, User> userCache
= new Dictionary<string, User>();
static void Main(string[] args)
{
// 启动两个读线程
new Thread(ReadCache) { IsBackground = true }.Start();
new Thread(ReadCache) { IsBackground = true }.Start();
// 启动一个写线程
new Thread(WriteCache) { IsBackground = true }.Start();
Console.ReadLine();
}
static void ReadCache()
{
while (true)
{
foreach (var item in userCache)
{
Thread.Sleep(5);
}
}
}
static void WriteCache()
{
int id = 0;
while (true)
{
User user = new User()
{
Name = "user" + id.ToString(),
Password = id.ToString("d7")
};
userCache.Add(user.Name, user);
Thread.Sleep(1000);
}
}
}
}
程序运行后,很快抛出异常

2. 实现线程安全的泛型集合SafeDictionary<TKey, TValue>
利用System.Thread. ReaderWriterLockSlim锁实现线程安全的泛型集合SafeDictionary<TKey, TValue>。SafeDictionary<TKey, TValue>支持多个线程并发读取;
public class SafeDictionary<TKey, TVlue> : IEnumerable<KeyValuePair<TKey, TVlue>> { private readonly Dictionary<TKey, TVlue> storage; private ReaderWriterLockSlim rwLock; public SafeDictionary() { rwLock = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion); storage = new Dictionary<TKey, TVlue>(); } public TVlue this[TKey key] { get { TVlue value = default(TVlue); try { rwLock.EnterReadLock(); storage.TryGetValue(key, out value); } finally { rwLock.ExitReadLock(); } return value; } } public void Add(TKey key, TVlue value) { try { rwLock.EnterUpgradeableReadLock(); if (storage.ContainsKey(key)) return; try { rwLock.EnterWriteLock(); storage.Add(key, value); } finally { rwLock.ExitWriteLock(); } } finally { rwLock.ExitUpgradeableReadLock(); } } public bool Remove(TKey key) { try { rwLock.EnterWriteLock(); return storage.Remove(key); } finally { rwLock.ExitWriteLock(); } } public List<KeyValuePair<TKey, TVlue>> ToList() { try { rwLock.EnterReadLock(); return storage.ToList(); } finally { rwLock.ExitReadLock(); } } public List<TKey> GetKeyList() { try { rwLock.EnterReadLock(); return storage.Keys.ToList(); } finally { rwLock.ExitReadLock(); } } public List<TVlue> GetValueList() { try { rwLock.EnterReadLock(); return storage.Values.ToList(); } finally { rwLock.ExitReadLock(); } } public int Count { get { try { rwLock.EnterReadLock(); return storage.Count; } finally { rwLock.ExitReadLock(); } } } public void Clear() { try { rwLock.EnterWriteLock(); storage.Clear(); } finally { rwLock.ExitWriteLock(); } } public IEnumerator<KeyValuePair<TKey, TVlue>> GetEnumerator() { try { rwLock.EnterReadLock(); foreach (var item in storage) { yield return item; } } finally { rwLock.ExitReadLock(); } } System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return GetEnumerator(); } }
ReaderWriterLockSlim提供两种锁定方式:“写锁定(wirte lock)”和“读锁定(read lock)”。任何时刻,ReaderWriterLockSlim只允许1个线程获取“写锁定”。获取了“写锁定”的线程将阻止其他已经获取“读锁定”的线程对资源的读取操作;如果当前没有获取“写锁定”的线程,那么,多个获取“读锁定”的线程可以同时对资源进行读取操作。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
namespace SafeDictionaryTest
{
class Program
{
static SafeDictionary<string, User> userCache;
static volatile int id = 0;
static void Main(string[] args)
{
userCache = new SafeDictionary<string, User>();
// 两个读线程
new Thread(ReadCache) { IsBackground = true }.Start();
new Thread(ReadCache) { IsBackground = true }.Start();
// 两个写线程
new Thread(WriteCache) { IsBackground = true }.Start();
new Thread(WriteCache) { IsBackground = true }.Start();
// 两个删除线程
new Thread(DeletUser) { IsBackground = true }.Start();
new Thread(DeletUser) { IsBackground = true }.Start();
Console.ReadLine();
}
static void ReadCache()
{
while (true)
{
foreach (var v in userCache)
{
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("{0} {1}", v.Key, v.Value.Password);
}
Console.WriteLine("-------------------------------");
Thread.Sleep(1000);
}
}
static void WriteCache()
{
while (true)
{
id++;
string name = "user" + id.ToString();
string password = id.ToString("d7");
User user = new User() { Name = name, Password = password };
userCache.Add(name, user);
Thread.Sleep(1000);
}
}
static void DeletUser()
{
Random rnd = new Random();
while (true)
{
string key = "user" + rnd.Next(1, id).ToString();
if (userCache.Remove(key))
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("{0} Deleted", key);
}
Thread.Sleep(50);
}
}
}
}

浙公网安备 33010602011771号