Java中的ConcurrentHashMap原理分析节选

集合是编程中最常用的数据结构。而谈到并发,几乎总是离不开集合这类高级数据结构的支持。比如两个线程需要同时访问一个中间临界区Queue,比如常会用缓存作为外部文件的副本HashMap。这篇文章主要分析jdk1.5的3种并发集合类型concurrent,copyonright,queue中的ConcurrentHashMap,让我们从原理上细致的了解它们,能够让我们在深度项目开发中获益非浅。
    
在tiger之前我们使用得最多的数据结构之一就是HashMap和Hashtable。大HashMap中未进行同步考虑,而Hashtable则使用了synchronized,带来的直接影响就是可选择,我们可以在单线程时使用HashMap提高效率,而多线程时用Hashtable来保证安全。
    
当享受着jdk带来的便利时同样承受它带来的不幸恶果。通过分析Hashtable就知道,synchronized是针对整张Hash表的,即每次锁住整张表让线程独占,安全的背后是巨大的浪费,慧眼独具的Doug Lee立马拿出了解决方案----ConcurrentHashMap。
    

ConcurrentHashMap和Hashtable主要区别就是围绕着锁的粒度以及如何锁。


左边便是Hashtable的实现方式---锁整个hash表;而右边则是ConcurrentHashMap的实现方式---锁桶(或段)。ConcurrentHashMap将hash表分为16个桶(默认值),诸如get,put,remove等常用操作只锁当前需要用到的桶。试想,原来只能一个线程进入,现在却能同时16个写线程进入(写线程才需要锁定,而读线程几乎不受限制,之后会提到),并发性的提升是显而易见的。

更令人惊讶的是ConcurrentHashMap的读取并发,因为在读取的大多数时候都没有用到锁定,所以读取操作几乎是完全的并发操作,而写操作锁定的粒度又非常细,比起之前又更加快速(这一点在桶更多时表现得更明显些)。只有在求size等操作时才需要锁定整个表。而在迭代时,ConcurrentHashMap使用了不同于传统集合的快速失败迭代器(见之前的文章《JAVA API备忘---集合》)的另一种迭代方式,我们称为弱一致迭代器。在这种迭代方式中,当iterator被创建后集合再发生改变就不再是抛出ConcurrentModificationException,取而代之的是在改变时new新的数据从而不影响原有的数据,iterator完成后再将头指针替换为新的数据,这样iterator线程可以使用原来老的数据,而写线程也可以并发的完成改变,更重要的,这保证了多个线程并发执行的连续性和扩展性,是性能提升的关键。

原帖地址:http://blog.csdn.net/liuzhengkang/article/details/2916620

时间: 2024-10-31 03:54:35

Java中的ConcurrentHashMap原理分析节选的相关文章

java中HashMap的原理分析_java

我们先来看这样的一道面试题: 在 HashMap 中存放的一系列键值对,其中键为某个我们自定义的类型.放入 HashMap 后,我们在外部把某一个 key 的属性进行更改,然后我们再用这个 key 从 HashMap 里取出元素,这时候 HashMap 会返回什么? 文中已给出示例代码与答案,但关于HashMap的原理没有做出解释. 1. 特性 我们可以用任何类作为HashMap的key,但是对于这些类应该有什么限制条件呢?且看下面的代码: public class Person { priva

彻底理解引用在 Android 和 Java 中的工作原理

本文讲的是彻底理解引用在 Android 和 Java 中的工作原理, 几周前,我很荣幸地参加了在波兰举行的 Mobiconf ,移动开发者参加的最好的研讨会之一.我的朋友兼同事 Jorge Barroso 做了个名为"最好(良好)的做法"的演说 ,这让我在听后很有感触: 对于一个 Android 开发者,如果你不使用 WeakReferences,这是有问题的. 举个恰当的例子,几个月前,我发布了我的最后一本书 "Android High Performance"

java 中ClassLoader的原理

本文转载自:http://blog.csdn.net/xyang81/article/details/7292380 一.什么是ClassLoader?          大家都知道,当我们写好一个Java程序之后,不是管是CS还是BS应用,都是由若干个.class文件组织而成的一个完整的Java应用程序,当程序在运行时,即会调用该程序的一个入口函数来调用系统的相关功能,而这些功能都被封装在不同的class文件当中,所以经常要从这个class文件中要调用另外一个class文件中的方法,如果另外一

Java阻塞队列实现原理分析

Java中的阻塞队列接口BlockingQueue继承自Queue接口. BlockingQueue接口提供了3个添加元素方法: add:添加元素到队列里,添加成功返回true,由于容量满了添加失败会抛出IllegalStateException异常; offer:添加元素到队列里,添加成功返回true,添加失败返回false; put:添加元素到队列里,如果容量满了会阻塞直到容量不满. 3个删除方法: poll:删除队列头部元素,如果队列为空,返回null.否则返回元素; remove:基于对

Java 框架 Netty 实现原理分析

文将主要分析Netty实现方面的东西,由于精力有限,本人并没有对其源码做了极细致的研 究.如果下面的内容有错误或不严谨的地方,也请指正和谅解.对于Netty使用者来说,Netty提供了几个典型的example,并有详尽的API doc和guide doc,本文的一些内容及图示也来自于Netty的文档,特此致谢. 1.总体结构 先放上一张漂亮的Netty总体结构图,下面的内容也主要围绕该图上的一些核心功能做分析,但对如Container Integration及Security Support等高

java中transient关键字用法分析_java

本文实例分析了java中transient关键字用法.分享给大家供大家参考.具体分析如下: java有个特点就是序列化,简单地来说就是可以将这个类存储在物理空间(当然还是以文件的形式存在),那么当你从本地还原这个文件时,你可以将它转换为它本身.这可以极大地方便网络上的一些操作,但同时,因为涉及到安全问题,所以并不希望把类里面所有的东西都能存储(因为那样,别人可以通过序列化知道类里面的内容),那么我们就可以用上transient这个关键字,它的意思是临时的,即不会随类一起序列化到本地,所以当还原后

ucenter中词语过滤原理分析_php技巧

本文分析了ucenter中词语过滤原理.分享给大家供大家参考,具体如下: 过滤词语表: id admin find replacement findpattern 1 UCenterAdminist 访问 大 /访问/is 2 UCenterAdminist 4655 45 /4655/is 3 UCenterAdminist fdsaf dfsa /fdsaf/is 4 UCenterAdminist 有机会 在 /有机会/is 组建缓存数据: //private function _get_

基于java中反射的总结分析_java

刚开始学习java的时候真的很难理解反射到底是个什么东西 一些书籍,哪怕是很经典的书籍都解释的让人感觉懵懵的,或许的确是我太笨 况且,网上说在将来学习框架的时候需要经常应用到反射机制,这样一来总让人心里有些不安 就方才偶然又把讲解反射的章节和视频看了一点,觉得能理解一些了 现在决定一鼓作气,边看边写,顺便把一些主要的内容和操作都记载到这里 我想,对于我这么一个笨笨的人来说,学习的最好方法也许就是不断重复 遇到不懂的知识就停下来把以往的重新学一遍,虽然浪费了很多时间,但对我也有些效果   我的理解

Java中的代理原理及代理使用示例_java

今天再测试Socket编程时,无法连接外网.公司用的是Http的代理.上网搜索也没看太懂,所以花了大量时间来学习.看了HTTP和TCP协议的关系好,才有所明白.现在能通过Socket使用HTTP代理了,结果很简单,过程却好难. 1. 先简要说说HTTP和TCP(具体内容自行Google,资料很多很全),这里就讲讲要点: HTTP:是应用层协议,是基于传输层协议的. TCP: 是传输层协议,是基于网络层协议的. IP: 是网络层协议. 一个TCP的连接要进行三次握手(就像转户口一样,不详说),HT