预备知识:Java HashMap and HashSet 的实现机制

由预备知识可以知道hashmap 的存储结构为:

(图像来自http://www.ibm.com/developerworks/cn/java/j-lo-hash/

也是说:一个hashmap 内部含有一个Entity 类行的数组,这个数组中的元素都是Entity。实际上我们放入map 中的key 和 value 就对应一个Entity 对象,这个Entity 对象包含一个key、value、hashcode(key 的)和一个Entity 的引用,通过这个引用,Entity 可以形成一个链表。在图中,蓝色矩形方框代表数组,橙色椭圆代表Entity 对象。

注意HashMap 类不是线程安全的。

ConcurrentMap  主要的子类是ConcurrentHashMap。

原理:一个ConcurrentHashMap 由多个segment 组成,每个segment 包含一个Entity 的数组。这里比HashMap 多了一个segment 类。该类继承了ReentrantLock 类,所以本身是一个锁。当多线程对ConcurrentHashMap 操作时,不是完全锁住map, 而是锁住相应的segment 。这样提高了并发效率。

构造函数的分析:

  /** 

     * Creates a new, empty map with a default initial capacity (16), 

     * load factor (0.75) and concurrencyLevel (16). 

     */  

  public ConcurrentHashMap() {  

    this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL);  

    }  

这是ConcurrentHashMap 的无参构造函数,可以看到默认大小为16,负载因子0.75,并发级别为16.

Put 函数的分析:

  /** 

     * Maps the specified key to the specified value in this table. 

     * Neither the key nor the value can be null. 

     * 

     * <p> The value can be retrieved by calling the <tt>get</tt> method 

     * with a key that is equal to the original key. 

     * 

     * @param key key with which the specified value is to be associated 

     * @param value value to be associated with the specified key 

     * @return the previous value associated with <tt>key</tt>, or 

     *         <tt>null</tt> if there was no mapping for <tt>key</tt> 

     * @throws NullPointerException if the specified key or value is null 

     */  

  public V put(K key, V value) {  

    if (value == null)  

    throw new NullPointerException();  

    int hash = hash(key.hashCode());  

    return segmentFor(hash).put(key, hash, value, false);  

    }  

可以看出通过hash() 函数得到key 的哈希值,在得到相应的segment,在通过segment 存储Entity。

同时为了避免“检测再修改”(有条件线程安全参见[2])等并发问题,ConcurrentHashMap 提供了putIfAbsent(K key, V value)  方法,当key 不存在时,添加。(key 的存在靠两个条件,一个是key的hashcode方法,另外一个是key 的equal 方法)

优点:由于对对应segment  加锁,而不是锁定整个map,并发性得到了提高。能够直接提高插入、检索以及移除操作的可伸缩性。

缺点:当遍历map 中的元素时,需要获取所有的segment 的锁,使用遍历时慢。锁的增多,占用了系统的资源。使得对整个集合进行操作的一些方法(例如 size() 或 isEmpty() )的实现更加困难,因为这些方法要求一次获得许多的锁,并且还存在返回不正确的结果的风险。

【转】ConcurrentMap 分析和思考的更多相关文章

  1. 我对Padding Oracle Attack的分析和思考

    道哥的<白帽子讲web安全>有一章提到Padding Oracle Attack的攻击方式,据说这货在2011年的Pwnie Rewards上还被评为"最具价值的服务器漏洞&qu ...

  2. Linux内核分析:页回收导致的cpu load瞬间飙高的问题分析与思考--------------蘑菇街技术博客

    http://mogu.io/156-156 摘要 本文一是为了讨论在Linux系统出现问题时我们能够借助哪些工具去协助分析,二是讨论出现问题时大致的可能点以及思路,三是希望能给应用层开发团队介绍一些 ...

  3. 关于 SSV-ID: 4474 POC的分析和思考

    SSV-ID: 4474 SSV-AppDir: Discuz!漏洞 发布时间: 2008-11-21 (GMT+0800) URL:http://sebug.net/vuldb/ssvid-4474 ...

  4. Linux-某电商网站流量劫持案例分析与思考

    [前言] 自腾讯与京东建立了战略合作关系之后,笔者网上购物就首选京东了.某天在家里访问京东首页的时候突然吃惊地发现浏览器突然跳到了第三方网站再回到京东,心里第一个反应就是中木马了. 竟然有这样的事,一 ...

  5. memcache redundancy机制分析及思考

    设计和开发可以掌控客户端的分布式服务端程序是件幸事,可以把很多事情交给客户端来做,而且可以做的很优雅.角色决定命运,在互联网架构中,web server必须冲锋在前,注定要在多浏览器版本以及协议兼容性 ...

  6. WEB项目日志分析系统思考

    一.为什么需要日志分析系统 对ETL系统中数据转换和存储操作的相关日志进行记录以及实时分析有助于我们更好的观察和监控ETL系统的相关指标(如单位时间某些操作的处理时间),发现系统中出现的缺陷和性能瓶颈 ...

  7. 关于MySQL集群架构优劣势与适用场景的分析与思考

    http://blog.itpub.net/25723371/viewspace-1977389/

  8. datax分析与思考(一)

    Datax 总体流程图 先看执行的第一个步骤: 在最上层抽象类,这个里面相当于获取全局公共信息,java入口部分就是这个Engine的main方法直接启动 Engine 启动 com.alibaba. ...

  9. DDD实践问题之 - 关于论坛的帖子回复统计信息的更新的思考

    之前,在用ENode开发forum案例时,遇到了关于如何实现论坛帖子的回复的统计信息如何更新的问题.后来找到了自己认为比较合理的解决方案,分享给大家.也希望能和大家交流,擦出更多的火花. 论坛核心领域 ...

随机推荐

  1. FC 协议

    FC 协议简介 开发于1988年,最早是用来提高硬盘协议的传输带宽,侧重于数据的快速.高效.可靠传输.到上世纪90年代末, FC SAN 开始得到大规模的广泛应用. FC 协议其实并不能翻译成光纤协议 ...

  2. 使用maven打包额外的jar

    当使用maven打包的时候,部分自己的额外使用的在maven基础库里面是没有的时候: 参考:  https://blog.csdn.net/hguisu/article/details/5107268 ...

  3. "==" 与 “equals”

    “==”: “==”或等号操作在Java编程语言中是一个二元操作符,用于比较原生类型和对象.(操作符不支持重载overloading) “==”对比两个对象基于内存引用,如果两个对象的引用完全相同(指 ...

  4. python mac下使用多进程报错解决办法

    使用pychram运行python web,web使用了多进程 mac下运行会提示如下: may have been in progress in another thread when fork() ...

  5. Ceph系统的层次结构

      Ceph存储系统的逻辑层次结构如下图所示[1]. Ceph系统逻辑层次结构自下向上,可以将Ceph系统分为四个层次: (1)基础存储系统RADOS(Reliable, Autonomic, Dis ...

  6. ansible初识二

    一.ansible模块(yum.pip.service.conr.user.group) 上篇中我们已经学了ansible 的几个模块, 接下来再来学习几个, 那么你是否知道ansible 一共有多少 ...

  7. Rhythmk 一步一步学 JAVA(9) JAVA 基础笔记[枚举,...]

    1.装箱就是值类型转换为object类型,拆箱相反:object转化为值类型 eg:Integer i=1; // 装箱 int j=i; // 拆箱 2.静态导入: eg: 导入: import s ...

  8. TortoiseSVN/Git覆盖图标失效的解决方案

    之前在电脑上安装了TortoiseGit和TortoiseSVN这两种版本控制,使用一段时间之后发现,这两种版本控制的覆盖图标都无法显示,起初以为是git和svn使用的图标的不一样,有冲突,导致这两种 ...

  9. 关于微软的.NET版本系列

    .net的不同版本的区分,感觉十分坑,搞开发的不能还去研究他们的版本含义或差异吧!下面为整理的一些相关内容: 一..NET的那些版本 .net framework 版本是可以向后兼容的,安装高版本的可 ...

  10. django html模板继承 {%block 标记名} {%endblock%}

    对于url文件 url(r'^tp1/', views.tp1) 对于views文件,跳转到tp1.html 同时将list列表传到前端 def tp1(request): list = [1, 2, ...