可以以不同的方式看待线程安全集合与非线程安全集合。
考虑一家没有店员的商店,除了结账处。如果人们不负责任地行事,就会遇到很多问题。例如,假设一位顾客从金字塔罐中取出一个罐头,而一名店员正在建造金字塔,那么一切都会崩溃。或者,如果两个顾客同时购买同一件商品,谁会获胜?会打架吗?这是一个非线程安全集合。有很多方法可以避免问题,但它们都需要某种锁定,或者更确切地说以某种方式显式访问。
另一方面,考虑一家商店,柜台前有一名店员,你只能通过他购物。你排队,向他要一样东西,他把东西还给你,然后你就离开队伍。如果您需要多件商品,每次往返只能领取您记得的商品数量,但您需要小心,避免霸占店员,这会激怒后面排队的其他顾客。
现在考虑一下这一点。在只有一名店员的商店里,如果你一直排到队伍的最前面,问店员“你们有卫生纸吗?”他说“有”,然后你说:“好吧,我”当我知道我需要多少时,我会回复你”,那么当你回到队伍前面时,商店当然可以卖完。线程安全集合无法阻止这种情况。
线程安全集合保证其内部数据结构始终有效,即使是从多个线程访问也是如此。
非线程安全集合不提供任何此类保证。例如,如果您在一个线程上向二叉树添加某些内容,而另一个线程正忙于重新平衡该树,则无法保证该项目会被添加,或者即使该树之后仍然有效,它也可能会被破坏得超出希望。
然而,线程安全集合并不能保证线程上的顺序操作都在其内部数据结构的同一个“快照”上工作,这意味着如果您有如下代码:
if (tree.Count > 0)
Debug.WriteLine(tree.First().ToString());
你可能会得到一个 NullReferenceException 因为中间tree.Count
and tree.First()
,另一个线程已经清除了树中剩余的节点,这意味着First()
将返回null
.
对于这种情况,您要么需要查看相关集合是否有安全的方法来获取您想要的内容,也许您需要重写上面的代码,或者您可能需要锁定。