预备知识: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. SpringBoot运行报Address already in use: bind

    java.net.BindException: Address already in use: bind at sun.nio.ch.Net.bind0(Native Method) at sun.n ...

  2. 【kubernetes】kubectl logs connection refused

    因为启动dashboard报CrashLoopBackOff错误,尝试使用logs去查看日志,结果报错,错误如下: [root@localhost ~]# kubectl -s http://192. ...

  3. Spring Framework中常见的事务传播陷阱(译文)

    最近看到Medium上一篇讨论Spring Framework中事务传播的文章,解释了几种常见的问题,解释的不错,这里直接翻译吧(意译为主,粗体和斜体是我自己加上的). 译文: 这是我的第一篇文章,我 ...

  4. java代码----I/O流从控制台输入信息判断并抛出异常

    package com.a.b; import java.io.*; public class Yu { public static void main(String[] args) throws I ...

  5. 螺旋填数:读入两个整数m,n,输出一个m行n列的矩阵,这个矩阵是1~m*n这些自然数按照右、下、左、上螺旋填入的结果。

    package Day8_06; /*读入两个整数m,n,输出一个m行n列的矩阵,这个矩阵是1~m*n这些自然数按照右.下.左.上螺旋填入的结果. * 例如读入数字4,5,则输出结果为: * 1 2 ...

  6. CentOS7 php7 安装 curl 扩展

    直接从php源码包中,使用root权限安装. 找到原先安装PHP的源码包文件(如果已经删掉需要重新下载原来版本的源码包并解压) 我的php源码包在root家目录下. cd /php-7.1.4/ext ...

  7. [转][c#]注册表经验集

    在 win7 64位的系统中,为了将程序做成绿化版(单EXE文件),一些设置准备放到 regedit(注册表)中. 测试时发现网上的 demo 可以读,但写的值调试不报错,相应位置却不存在,困扰了许久 ...

  8. node中的ajax提交小例子

    我们看一个HTML5页面中通过AJAX请求的方式获取HTTP服务器返回数据的代码示例.由于我们把服务器的端口指定为1337,并将从端口为80的网站中运行HTML5页面,因此这是一种跨域操作,需要在HT ...

  9. 5月12日上课笔记-js 弹出框、函数、程序调试、基本事件、浏览器对象模型

    一.弹出框 a.提示框 alert(); b.输入框 prompt(); c.确认框 confirm(); var flag= confirm("确认删除吗?"); 二.js程序调 ...

  10. Vue语法

    第一个Vue示例: <!DOCTYPE html> <html lang="en"> <head> <meta charset=" ...