【转】ConcurrentMap 分析和思考
预备知识: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 分析和思考的更多相关文章
- 我对Padding Oracle Attack的分析和思考
道哥的<白帽子讲web安全>有一章提到Padding Oracle Attack的攻击方式,据说这货在2011年的Pwnie Rewards上还被评为"最具价值的服务器漏洞&qu ...
- Linux内核分析:页回收导致的cpu load瞬间飙高的问题分析与思考--------------蘑菇街技术博客
http://mogu.io/156-156 摘要 本文一是为了讨论在Linux系统出现问题时我们能够借助哪些工具去协助分析,二是讨论出现问题时大致的可能点以及思路,三是希望能给应用层开发团队介绍一些 ...
- 关于 SSV-ID: 4474 POC的分析和思考
SSV-ID: 4474 SSV-AppDir: Discuz!漏洞 发布时间: 2008-11-21 (GMT+0800) URL:http://sebug.net/vuldb/ssvid-4474 ...
- Linux-某电商网站流量劫持案例分析与思考
[前言] 自腾讯与京东建立了战略合作关系之后,笔者网上购物就首选京东了.某天在家里访问京东首页的时候突然吃惊地发现浏览器突然跳到了第三方网站再回到京东,心里第一个反应就是中木马了. 竟然有这样的事,一 ...
- memcache redundancy机制分析及思考
设计和开发可以掌控客户端的分布式服务端程序是件幸事,可以把很多事情交给客户端来做,而且可以做的很优雅.角色决定命运,在互联网架构中,web server必须冲锋在前,注定要在多浏览器版本以及协议兼容性 ...
- WEB项目日志分析系统思考
一.为什么需要日志分析系统 对ETL系统中数据转换和存储操作的相关日志进行记录以及实时分析有助于我们更好的观察和监控ETL系统的相关指标(如单位时间某些操作的处理时间),发现系统中出现的缺陷和性能瓶颈 ...
- 关于MySQL集群架构优劣势与适用场景的分析与思考
http://blog.itpub.net/25723371/viewspace-1977389/
- datax分析与思考(一)
Datax 总体流程图 先看执行的第一个步骤: 在最上层抽象类,这个里面相当于获取全局公共信息,java入口部分就是这个Engine的main方法直接启动 Engine 启动 com.alibaba. ...
- DDD实践问题之 - 关于论坛的帖子回复统计信息的更新的思考
之前,在用ENode开发forum案例时,遇到了关于如何实现论坛帖子的回复的统计信息如何更新的问题.后来找到了自己认为比较合理的解决方案,分享给大家.也希望能和大家交流,擦出更多的火花. 论坛核心领域 ...
随机推荐
- 第六章 hbase shell 命令
hbase shell命令 描述 alter 修改列族(Column Family)模式 count 统计表中行的数量 create 创建表 ...
- 设计模式——单例模式(C++)
一: 饿汉式单例: 静态区初始化instance,然后通过getInstance返回.这种方式没有多线程的问题,是一种以空间换时间的方式,不管程序用不用,都会构造唯一的实例. #pragma once ...
- ALSA声卡笔记1---ALSA驱动框架
1.声卡驱动程序sound.c (1)入口函数里通过register_chrdev()函数注册file_operations 结构体 (2)file_operations 结构体,里面只有open函数 ...
- 【BZOJ】1878: [SDOI2009]HH的项链 (主席树)
题目 传送门:QWQ 分析 莫队也能做,但我想练练主席树. 求k-th一样维护第i个时候的线段树,线段树来维护区间不同数. 然后查询时可以通过上下界小优化一波. 但是我的代码丑陋无比,常数巨大(捂脸 ...
- Julia - 匿名函数
Julia 中的函数可以被匿名构造,成为匿名函数,匿名函数是没有函数名的函数 julia> x -> x + 1 #3 (generic function with 1 method) 这 ...
- ISIS与OSPF的区别与联系
共同之处: 1 都是链路状态路由协议,都要求区域内的路由器交换链路状态信息,链路状态信息被收集到链路状态数据库中 2 都是用了一种实现路由选择信息交换相似机制 3 都在广播网络中选择指定路由器来控制扩 ...
- MaxScript 学习笔记【有转载】
1. string string类型的变量是一个数组,下列操作合法:strName = $.name -- output: "Shemmy_03" strName[1] --得到字 ...
- mysql 如何清除sql缓存
对一条sql进行优化时,发现原本很慢的一条sql(将近1分钟) 在第二次运行时, 瞬间就完成了(.00sec) 这是因为mysql对同一条sql进行了缓存,服务器直接从上次的查询结果缓存中读取数据,而 ...
- Boost在Linux 64 下的编译
1. 下载最新版的boost wget https://dl.bintray.com/boostorg/release/1.67.0/source/boost_1_67_0.tar.gz 2. 解压 ...
- 从socket开始讲IOS网络编程
home list tags talk user rss Mac&iOS Socket 大纲 一.Socket简介 二.BSD Socket编程准备 1.地址 2.端口 3.网络字节序 4.半 ...