您的实现是正确的。不幸的是,. net框架没有提供内置并发哈希集类型。然而,有一些变通办法。
ConcurrentDictionary最后(推荐)
第一个是在命名空间System.Collections.Concurrent中使用类ConcurrentDictionary<TKey, TValue>。在这种情况下,值是没有意义的,所以我们可以使用一个简单的字节(内存中的1个字节)。
private ConcurrentDictionary<string, byte> _data;
这是推荐的选项,因为该类型是线程安全的,并且提供了与HashSet<T>相同的优点,除非key和value是不同的对象。
资料来源:社会化MSDN
Self-implementation
最后,正如您所做的,您可以实现自己的数据类型,使用锁或其他。net提供的线程安全的方法。这里有一个很好的例子:如何在。net中实现ConcurrentHashSet
这个解决方案的唯一缺点是类型HashSet<T>不能正式并发访问,即使是读取操作。
我引用了链接帖子的代码(最初由Ben Mosher编写)。
using System;
using System.Collections.Generic;
using System.Threading;
namespace BlahBlah.Utilities
{
public class ConcurrentHashSet<T> : IDisposable
{
private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
private readonly HashSet<T> _hashSet = new HashSet<T>();
#region Implementation of ICollection<T> ...ish
public bool Add(T item)
{
_lock.EnterWriteLock();
try
{
return _hashSet.Add(item);
}
finally
{
if (_lock.IsWriteLockHeld) _lock.ExitWriteLock();
}
}
public void Clear()
{
_lock.EnterWriteLock();
try
{
_hashSet.Clear();
}
finally
{
if (_lock.IsWriteLockHeld) _lock.ExitWriteLock();
}
}
public bool Contains(T item)
{
_lock.EnterReadLock();
try
{
return _hashSet.Contains(item);
}
finally
{
if (_lock.IsReadLockHeld) _lock.ExitReadLock();
}
}
public bool Remove(T item)
{
_lock.EnterWriteLock();
try
{
return _hashSet.Remove(item);
}
finally
{
if (_lock.IsWriteLockHeld) _lock.ExitWriteLock();
}
}
public int Count
{
get
{
_lock.EnterReadLock();
try
{
return _hashSet.Count;
}
finally
{
if (_lock.IsReadLockHeld) _lock.ExitReadLock();
}
}
}
#endregion
#region Dispose
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
if (_lock != null)
_lock.Dispose();
}
~ConcurrentHashSet()
{
Dispose(false);
}
#endregion
}
}
EDIT:将入口锁方法移到try块之外,因为它们可以抛出异常并执行finally块中包含的指令。
ConcurrentBag(不建议)
不建议使用ConcurrentBag<T>,因为这种类型只允许以线程安全的方式插入给定的元素和删除随机元素。这个类是为促进生产者-消费者场景而设计的,这不是OP的目标(更多解释在这里)。
其他操作(例如,扩展方法提供的操作)不支持并发使用。MSDN文档警告:“ConcurrentBag的所有公共和受保护成员都是线程安全的,可以从多个线程并发使用。然而,通过ConcurrentBag实现的接口之一访问的成员,包括扩展方法,不保证是线程安全的,可能需要由调用者同步。”