Java 并发编程(四)并发容器

并发容器

Java 5.0 提供了多种并发容器来改进同步容器的性能。

        同步容器是将所有对容器的访问都串行化,以实现他们的线程安全性。代价是严重降低并发行,当多个线程竞争容器的锁时,吞吐量将严重降低。

        并发容器是针对多个线程并发访问设计的。 Java 5.0 增加了
ConcurrentHashMap ,用来替代同步且基于散列的 Map ,增加了
CopyOnWriteArrayList ,用于在遍历操作为主要操作的情况下替代同步的 List 。

Java 5.0 还增加了两中心的容器类型:Queue
BlockingQAueue

Queue 用来临时保存待处理的元素。它提供了几种实现,包括 ConcurrentLinkedQueue,这是一个传统的先进先出队列。PriorityQueue,这是一个(非并发的)优先队列。Queue 上的操作不会阻塞,如果队列为空,那么获取元素的操作将返回空值。虽然可以用 List 来模拟 Queue 的行为--事实上,正是通过 LinkedList 来实现 Queue 的,但还需一个 Queue 的类,因为它能去掉 List 的随机访问需求,从而实现更高效的并发。

BlockingQueue 扩展了 Queue,增加了可阻塞的插入和获取等操作。如果队列为空,那么获取元素的操作将一直阻塞,直到队列中出现了一个可用的元素。如果队列已满(对于有界队列),那么插入元素的操作将一直阻塞,直到队列中出现可用的空间。在生产者-消费者模式中,这是十分有用的

正如 ConcurrentHashMap 用于代替基于散列的同步 Map,Java 6 也引入了 ConcurrentSkipListMap
ConcurrentSkipListSet ,分别作为同步的 SortedMap 和 SortedSet 的并发替代品。(例如用 synchronizedMap 包装的 TreeMap 或 TreeSet)。

ConcurrentHashMap

基本结构上,ConcurrentHashMap 与 HashMap 一样,但它使用了一种完全不同的加锁策略来提供更高的并发性和伸缩性。它使用一种粒度更细的加锁机制来实现更大程度的共享,这种机制称为分段锁(Lock Striping)

采用分段锁,任意数量的读取线程可以并发的访问 Map,执行读取操作的线程和执行写入操作的线程可以并发的访问 Map,并且一定数量的写入线程可以并发的修改Map。ConcurrentHashMap 带来的结果是,在并发访问环境下将实现更高的吞吐量,而在单线程环境中只损失非常小的性能。

ConcurrentHashMap 与其他并发容器一起增强了同步容器类:他们提供的迭代器不会抛出 ConcurrentModificationException ,因此不需要在迭代过程中对容器加锁。ConcurrentHashMap 返回的迭代器具有弱一致性,而非 “及时失败”。弱一致性的迭代器可以容忍并发的修改,当创建迭代器时会遍历已有的元素,并可以在迭代器被构造后将修改操作反映给容器。

尽管有这些改进,但仍然有一些需要权衡的因素。对于一些需要在整个Map 上进行计算的方法,例如 size 和 isEmpty ,这些方法的寓意被略微减弱了以反映容器的并发特性。由于 size 方法返回的结果在计算时可能已经过期了,它实际上只是一个估计值,因此允许 size 返回一个近似值而不是一个精确值。虽然这看上去有些令人不安,但事实上 size 和 isEmpty 这样的方法在并发环境下的用处很小,因为他们的返回值总是在不断变化。因此,这些操作的需求被弱化了,以换取对其他更重要操作的性能优化,包括
get、put、containsKey 和 remove等。

与 Hashtable 和 synchronizedMap 相比,ConcurrentHashMap 有更多的优势以及更少的劣势。因此在大多数情况下,用 ConcurrentHashMap 来代替同步 Map 能进一步提高代码的可伸缩性。只有当应用程序需要加锁Map 以进行独占访问时,才能放弃使用 ConcurrentHashMap。

CopyOnWriteArrayList

CopyOnWriteArrayList 用于替代同步 List,在某些情况下,它提供了更好的并发性能。在迭代器件不需要对容器进行加锁或复制。(类似 CopyOnWriteArraySet)。

“写入时复制(Copy-On-Write)” 容器的线程安全性在于,只要正确的发布一个事实不可变对象,那么访问该对象时就不需要进一步的同步。每次修改的时候,都会创建并重新发布一个新的容器副本,从而实现可变性。“写入时复制”容器的迭代器保留一个指向底层基础数组的引用,这个数组当前位于迭代器的起始位置,由于他不会被修改,因此在对其进行同步时只需确保数组内容的可见性。因此,多个线程可以对这个容器进行迭代,而不会彼此干扰或者修改容器的线程相互干扰。

显然,每当修改容器时都会复制底层数组,这需要一定的开销,特别是当容器的规模较大时。晋档跌打操作远远多于修改操作时,才应该使用“写入时复制”容器。这个准则很好的描述了许多事件通知系统:

在分发通知时需要迭代已注册监听器链表,并调用每一个监听器,在大多数情况下,注册和注销事件监听器的操作远少于接收时间通知的操作。

时间: 2024-08-29 05:28:21

Java 并发编程(四)并发容器的相关文章

Java并发编程:并发容器ConcurrentHashMap

Java并发编程:并发容器之ConcurrentHashMap(转载) 下面这部分内容转载自: http://www.haogongju.net/art/2350374 JDK5中添加了新的concurrent包,相对同步容器而言,并发容器通过一些机制改进了并发性能.因为同步容器将所有对容器状态的访问都 串行化了,这样保证了线程的安全性,所以这种方法的代价就是严重降低了并发性,当多个线程竞争容器时,吞吐量严重降低.因此Java5.0开 始针对多线程并发访问设计,提供了并发性能较好的并发容器,引入

Java并发编程:并发容器之ConcurrentHashMap(转)

本文转自:http://www.cnblogs.com/dolphin0520/p/3932905.html Java并发编程:并发容器之ConcurrentHashMap(转载) 下面这部分内容转载自: http://www.haogongju.net/art/2350374 JDK5中添加了新的concurrent包,相对同步容器而言,并发容器通过一些机制改进了并发性能.因为同步容器将所有对容器状态的访问都 串行化了,这样保证了线程的安全性,所以这种方法的代价就是严重降低了并发性,当多个线程

Java并发编程:并发容器之CopyOnWriteArrayList(转)

本文转自:http://www.cnblogs.com/dolphin0520/p/3938914.html Java并发编程:并发容器之CopyOnWriteArrayList(转载) 原文链接: http://ifeve.com/java-copy-on-write/ Copy-On-Write简称COW,是一种用于程序设计中的优化策略.其基本思路是,从一开始大家都在共享同一个内容,当某个人想要修改这个内容的时候,才会真正把内容Copy出去形成一个新的内容然后再改,这是一种延时懒惰策略.从J

【转】Java并发编程:并发容器之ConcurrentHashMap

JDK5中添加了新的concurrent包,相对同步容器而言,并发容器通过一些机制改进了并发性能.因为同步容器将所有对容器状态的访问都串行化了,这样保证了线程的安全性,所以这种方法的代价就是严重降低了并发性,当多个线程竞争容器时,吞吐量严重降低.因此Java5.0开始针对多线程并发访问设计,提供了并发性能较好的并发容器,引入了java.util.concurrent包.与Vector和Hashtable.Collections.synchronizedXxx()同步容器等相比,util.conc

【Java并发编程】并发编程大合集-值得收藏

http://blog.csdn.net/ns_code/article/details/17539599这个博主的关于java并发编程系列很不错,值得收藏. 为了方便各位网友学习以及方便自己复习之用,将Java并发编程系列内容系列内容按照由浅入深的学习顺序总结如下,点击相应的标题即可跳转到对应的文章    [Java并发编程]实现多线程的两种方法    [Java并发编程]线程的中断    [Java并发编程]正确挂起.恢复.终止线程    [Java并发编程]守护线程和线程阻塞    [Ja

【Java并发编程】并发编程大合集

转载自:http://blog.csdn.net/ns_code/article/details/17539599 为了方便各位网友学习以及方便自己复习之用,将Java并发编程系列内容系列内容按照由浅入深的学习顺序总结如下,点击相应的标题即可跳转到对应的文章    [Java并发编程]实现多线程的两种方法    [Java并发编程]线程的中断    [Java并发编程]正确挂起.恢复.终止线程    [Java并发编程]守护线程和线程阻塞    [Java并发编程]Volatile关键字(上)

Java并发编程(四):并发容器(转)

解决并发情况下的容器线程安全问题的.给多线程环境准备一个线程安全的容器对象. 线程安全的容器对象: Vector, Hashtable.线程安全容器对象,都是使用 synchronized 方法实现的. concurrent 包中的同步容器,大多数是使用系统底层技术实现的线程安全.类似 native. Java8 中使用 CAS. 1.Map/Set 1.1 ConcurrentHashMap/ConcurrentHashSet 底层哈希实现的同步 Map(Set).效率高,线程安全.使用系统底

Java并发编程:同步容器

为了方便编写出线程安全的程序,Java里面提供了一些线程安全类和并发工具,比如:同步容器.并发容器.阻塞队列.Synchronizer(比如CountDownLatch).今天我们就来讨论下同步容器. 以下是本文的目录大纲: 一.为什么会出现同步容器? 二.Java中的同步容器类 三.同步容器的缺陷 若有不正之处请多多谅解,并欢迎批评指正. 请尊重作者劳动成果,转载请标明原文链接: http://www.cnblogs.com/dolphin0520/p/3933404.html 一.为什么会出

Java 并发编程(四):如何保证对象的线程安全性

本篇来谈谈 Java 并发编程:如何保证对象的线程安全性. 01.前言 先让我吐一句肺腑之言吧,不说出来会憋出内伤的.<Java 并发编程实战>这本书太特么枯燥了,尽管它被奉为并发编程当中的经典之作,但我还是忍不住.因为第四章"对象的组合"我整整啃了两周的时间,才啃出来点肉丝. 读者朋友们见谅啊.要怪只能怪我自己的学习能力有限,真读不了这种生硬无趣的技术书.但是为了学习,为了进步,为了将来(口号喊得有点大了),只能硬着头皮上. 请随我来,我尽量写得有趣点. 02.线程安全类

Java并发编程:并发容器之ConcurrentHashMap

下面这部分内容转载自: http://www.haogongju.net/art/2350374 JDK5中添加了新的concurrent包,相对同步容器而言,并发容器通过一些机制改进了并发性能.因为同步容器将所有对容器状态的访问都 串行化了,这样保证了线程的安全性,所以这种方法的代价就是严重降低了并发性,当多个线程竞争容器时,吞吐量严重降低.因此Java5.0开 始针对多线程并发访问设计,提供了并发性能较好的并发容器,引入了java.util.concurrent包.与Vector和Hasht