我正在学习Java集合框架(而不是Concurrent Collection框架),我发现一些Collection实现是线程安全的,有些则不是。
在我阅读的大多数材料中,所有提到的xyz
是线程安全的,abc
不是线程安全的。
但是,基于哪个决定是否保持给定的集合类型(例如,List,Set,Queue,甚至是Map ...)线程是否安全的逻辑是什么?
我的问题是参考"传统"集合框架而不是并发集合框架。
理解这一点的任何意见都会有很大的帮助。
答案 0 :(得分:4)
线程安全带来了开销(尽管在现代VM中,开销远低于设计集合框架时的开销)。因此除非特别需要,否则集合不是线程安全的,除了JDK1.1集合 - 当它们被设计时,哲学更像是"让我们留下很小的错误空间,以一些表现为代价"。
我们在Java API演变中有几个阶段。
在Java 1.1版中,我们有数据结构Vector
和Hashtable
。它们完全同步,提供一定程度的线程安全性。
在Java 1.2版中,引入了集合框架。所有基本集合都不是线程安全的(它们不会同步任何操作):ArrayList
,LinkedList
,HashMap
,TreeMap
和{{1}实现。
但您可以致电Set
,Collections.synchronizedMap
等获取同步版本。
在Java 1.5版本中,引入了Collections.synchronizedList
框架。它们包含为多线程使用而构建的专用数据。这些提供了一定程度的线程安全性。
请注意,即使使用同步集合,也可以引入数据竞争;它只意味着你不能破坏集合的内部结构(集合的所有不变量都将被维护)
例如,如果您有一个两步过程,首先检查集合中是否包含某个元素,并在第二步中插入该元素。如果您没有为这两个步骤提供自己的同步,那么如果两个线程同时执行此操作,则可以将元素添加两次。
答案 1 :(得分:1)
正如其他人所说,并发集合具有运行时和可能的内存开销,因此在线程安全和不安全集合中是分离的。
您可以在单线程库中找到的大多数数据结构都有几个线程安全的替代方案。一个值得注意的例外是List
,这可能是因为在应用程序中很少需要并发列表。
对于像队列和堆栈这样的东西,你有很多选择,因为让一个生产者和一个或几个消费者同时拉动和推动队列是很常见的事情。要实现缓存,您可能依赖于映射,这也是并发映射也得到很好支持的原因。
事实上,某些数据结构尚未真正反映在线程安全的API中,这仅仅是因为它们在多线程环境中通常不会有用。
答案 2 :(得分:-1)
原因很可能与表现有关。多线程之间的同步是一项昂贵的操作,尤其是对于大量元素集合。