基本上我有一个应用程序调用3个不同的线程,每个新的HashSet和我想知道的是这个线程是否安全?或者我是否需要在每个哈希集中添加[ThreadStatic]?
答案 0 :(得分:6)
如果您实例化三个不同的HashSet
,并且每个HashSet
只能由一个线程访问,那么它就没问题了。如果线程之间共享一个静态[ThreadStatic]
,则只需添加HashSet
属性。
[更新] 只是为了澄清[ThreadStatic]
的工作方式。
免责声明:我从不使用[ThreadStatic]
。该属性的存在会产生很多后果,这些后果并不明显,而且很难调试(以及正确测试)IMO。
假设你真的想在测试类中使用[ThreadStatic]
:
public class ThreadStaticTest
{
// CLR ensures that each thread accessing this field
// gets a separate instance of the *field*. This, however,
// means that static initializers don't work. Field is
// null at first access from an individual thread
[ThreadStatic]
static HashSet<string> _hashset;
// This is why we instantiate it explicitly here:
private HashSet<string> HashSet
{
get
{
_hashset = _hashset ?? new HashSet<string>();
return _hashset;
}
}
public void AddItem(string s)
{
// thread safe
HashSet.Add(s);
}
public IEnumerable<string> GetItems()
{
// thread safe
return HashSet;
}
}
运行以下控制台应用程序:
static void Main(string[] args)
{
// single test instance!
var test = new ThreadStaticTest();
List<Thread> threads = new List<Thread>();
for (int i = 0; i < 5; i++)
{
threads.Add(new Thread(() =>
{
var threadId = Thread.CurrentThread.ManagedThreadId;
test.AddItem("Hello from thread #" + threadId);
Console.WriteLine("Instance contains {0} items: '{1}'",
test.GetItems().Count(),
string.Join(", ", test.GetItems().ToArray()));
}));
}
threads.ForEach(t => t.Start());
threads.ForEach(t => t.Join());
Console.Read();
}
显示虽然只有一个测试实例,但每个线程都会获得一个新的hashset实例:
Instance contains 1 items: 'Hello from thread #11' Instance contains 1 items: 'Hello from thread #13' Instance contains 1 items: 'Hello from thread #10' Instance contains 1 items: 'Hello from thread #12' Instance contains 1 items: 'Hello from thread #14'
答案 1 :(得分:4)
根据HashSet
的MSDN文档:
此类型的任何公共静态(在Visual Basic中为Shared)成员都是线程安全的。不保证任何实例成员都是线程安全的。