我试图编写一个线程安全的方法,它只能被调用一次(每个对象实例)。如果之前被调用过,应抛出异常。如何:编写一个只能调用一次的线程安全方法?
我已经想出了两个解决方案。他们都是对的吗?如果没有,他们有什么问题?
随着
lock
:public void Foo() { lock (fooLock) { if (fooCalled) throw new InvalidOperationException(); fooCalled = true; } … } private object fooLock = new object(); private bool fooCalled;
随着
Interlocked.CompareExchange
:public void Foo() { if (Interlocked.CompareExchange(ref fooCalled, 1, 0) == 1) throw new InvalidOperationException(); … } private int fooCalled;
如果我没有记错的话,这个方案具有无锁的优势(这在我看来似乎并不相关),并且它需要更少的私人领域。
我也有理由认为哪个解决方案应该是首选的,如果还有更好的方法可以提出进一步的建议。
出于好奇:当你说它“不那么复杂”时,你似乎是指盲目背后发生的一切;你如何判断一个普通程序员的可读性/易于理解'Interlocked.ExchangeCompare'结构? – stakx 2012-03-01 10:51:57
@stakx:这就是评论。当一个程序员遇到他们不明白的东西时,他们应该查找它,以便他们理解它。这就是他们如何成为更好的程序员。 – thecoop 2012-03-01 10:53:23
@thecoop我不同意,是的这是最正确的解决方案,但它并不简单,您需要了解原子操作等。这是某种初始化过程,我建议遵循广泛使用的初始化模式(例如double检查锁)。此外,这些模式可以防止您错过执行线程时很容易发生的事情。 – ntziolis 2012-03-01 10:55:29