ConcurrentHashMap源码及分析
ConcurrentHashMap是在jdk1.5版本开始,存在于java.util.concurrent包下。本文主要是针对jdk1.7版本。
由于HashMap是非线程安全的,HashTable虽然是线程安全的,但是它的实现是对整个哈希表加锁,这样的话,效率很低下。
ConcurrentHashMap是线程安全的实现,像是对HashTable做的优化,但是它使用的是分段锁机制。ConcurrentHashMap的底层
也是使用基于数组+链表的数据结构。具体结构如下代码所示:
/**
* The segments, each of which is a specialized hash table.
*/
final Segment<K,V>[] segments;
内部使用的是Segment类型的数组结构,Segment是它的一个内部类,继承了ReentrantLock,表明数组中每个不同域Segment是加锁
的,互不影响。Segment的内部结构也是基于数组+链表的,具体代码是:
/**
* The per-segment table. Elements are accessed via
* entryAt/setEntryAt providing volatile semantics.
*/
transient volatile HashEntry<K,V>[] table;
内部使用的是HashEntry类型的数组,HashEntry就是内部存储的链表结构元素,它的具体实现如下:
final int hash;
final K key;
volatile V value;
volatile HashEntry<K,V> next; 上面我们介绍了ConcurrentHashMap的内部结构,接下来我们看下它的具体方法实现:
put方法:public V put(K key, V value) { Segment<K,V> s;
if (value == null)
throw new NullPointerException();
int hash = hash(key);
int j = (hash >>> segmentShift) & segmentMask;
if ((s = (Segment<K,V>)UNSAFE.getObject // nonvolatile; recheck
(segments, (j << SSHIFT) + SBASE)) == null) // in ensureSegment
s = ensureSegment(j);
return s.put(key, hash, value, false);
}
从源码看出,ConcurrentHashMap是不允许放入null的key和value,它是先根据key的hash值,再hash算法找到具体要放入哪个Segment。
ensureSegment方法是根据存入的键值对是否进行扩容。之后调用Segment进行分段加锁存入。 get方法:
public V get(Object key) {
Segment<K,V> s; // manually integrate access methods to reduce overhead
HashEntry<K,V>[] tab;
int h = hash(key);
long u = (((h >>> segmentShift) & segmentMask) << SSHIFT) + SBASE;
if ((s = (Segment<K,V>)UNSAFE.getObjectVolatile(segments, u)) != null &&
(tab = s.table) != null) {
for (HashEntry<K,V> e = (HashEntry<K,V>) UNSAFE.getObjectVolatile
(tab, ((long)(((tab.length - 1) & h)) << TSHIFT) + TBASE);
e != null; e = e.next) {
K k;
if ((k = e.key) == key || (e.hash == h && key.equals(k)))
return e.value;
}
}
return null;
}
从源码看出get取值是根据Key的hash及再hash算法找到具体的Segment。之后进行遍历,找出对应的value。此方法是没有进行加锁。 size方法:
public int size() {
// Try a few times to get accurate count. On failure due to
// continuous async changes in table, resort to locking.
final Segment<K,V>[] segments = this.segments;
int size;
boolean overflow; // true if size overflows 32 bits
long sum; // sum of modCounts
long last = 0L; // previous sum
int retries = -1; // first iteration isn't retry
try {
for (;;) {
if (retries++ == RETRIES_BEFORE_LOCK) {
for (int j = 0; j < segments.length; ++j)
ensureSegment(j).lock(); // force creation
}
sum = 0L;
size = 0;
overflow = false;
for (int j = 0; j < segments.length; ++j) {
Segment<K,V> seg = segmentAt(segments, j);
if (seg != null) {
sum += seg.modCount;
int c = seg.count;
if (c < 0 || (size += c) < 0)
overflow = true;
}
}
if (sum == last)
break;
last = sum;
}
} finally {
if (retries > RETRIES_BEFORE_LOCK) {
for (int j = 0; j < segments.length; ++j)
segmentAt(segments, j).unlock();
}
}
return overflow ? Integer.MAX_VALUE : size;
} 从源码看出它开始是没有进行加锁,先尝试得到size(最多尝试3次),若不正确,则进行所有Segmeng加锁进行统计大小。
本文只是对ConcurrentHashMap的结构和几个重要的方法做了简要分析,具体详情请看源码。
ConcurrentHashMap源码及分析的更多相关文章
- Hashtable、ConcurrentHashMap源码分析
Hashtable.ConcurrentHashMap源码分析 为什么把这两个数据结构对比分析呢,相信大家都明白.首先二者都是线程安全的,但是二者保证线程安全的方式却是不同的.废话不多说了,从源码的角 ...
- ConcurrentHashMap源码分析(一)
本篇博客的目录: 前言 一:ConcurrentHashMap简介 二:ConcurrentHashMap的内部实现 三:总结 前言:HashMap很多人都熟悉吧,它是我们平时编程中高频率出现的一种集 ...
- ConcurrentHashMap 源码分析
ConcurrentHashMap 源码分析 1. 前言 终于到这个类了,其实在前面很过很多次这个类,因为这个类代码量比较大,并且涉及到并发的问题,还有一点就是这个代码有些真的晦涩,不好懂.前前 ...
- 死磕 java集合之ConcurrentHashMap源码分析(三)
本章接着上两章,链接直达: 死磕 java集合之ConcurrentHashMap源码分析(一) 死磕 java集合之ConcurrentHashMap源码分析(二) 删除元素 删除元素跟添加元素一样 ...
- JDK(十)JDK1.7&1.8源码对比分析【集合】ConcurrentHashMap
前言 在JDK1.7&1.8源码对比分析[集合]HashMap中我们对比分析了JDK1.7和1.8版本的HashMap源码,趁热打铁,这篇文章就来看看JDK1.7和1.8版本的Concurre ...
- 并发-ConcurrentHashMap源码分析
ConcurrentHashMap 参考: http://www.cnblogs.com/chengxiao/p/6842045.html https://my.oschina.net/hosee/b ...
- JDK1.7 ConcurrentHashMap 源码浅析
概述 ConcurrentHashMap是HashMap的线程安全版本,使用了分段加锁的方案,在高并发时有比较好的性能. 本文分析JDK1.7中ConcurrentHashMap的实现. 正文 Con ...
- HashMap 与 ConcrrentHashMap 使用以及源码原理分析
前奏一:HashMap面试中常见问题汇总 HashMap的工作原理是近年来常见的Java面试题,几乎每个Java程序员都知道HashMap,都知道哪里要用HashMap,知道HashTable和Has ...
- JDK12 concurrenthashmap源码阅读
本文部分照片和代码分析来自文末参考资料 java8中的concurrenthashmap的方法逻辑和注解有些问题,建议看最新的JDK版本 建议阅读 concu ...
随机推荐
- Nhibernate学习教程(1)-- 开篇有益
NHibernate之旅(1):开篇有益 本节内容 NHibernate是什么 NHibernate的架构 NHibernate资源 欢迎加入NHibernate中文社区 作者注:2009-11-06 ...
- 团队作业八——第二次团队冲刺(Beta版本)第5天
团队作业八--第二次团队冲刺(Beta版本)第5天 一.每个人的工作 (1) 昨天已完成的工作 完成界面跳转界面. (2) 今天计划完成的工作 简单模式逻辑代码涉及与相关功能的具体实现 (3) 工作中 ...
- 201521123022 《Java程序设计》 第七周学习总结
1. 本周学习总结 以你喜欢的方式(思维导图或其他)归纳总结集合相关内容. 2. 书面作业 Q1.ArrayList代码分析 Q1.1 解释ArrayList的contains源代码 ArrayLis ...
- 201521123049 《JAVA程序设计》 第6周学习总结
1. 本周学习总结 1.1 面向对象学习暂告一段落,请使用思维导图,以封装.继承.多态为核心概念画一张思维导图,对面向对象思想进行一个总结. 注1:关键词与内容不求多,但概念之间的联系要清晰,内容覆盖 ...
- 201521123077 《Java程序设计》第1周学习总结
1. 本章学习总结 java语言的历史 dos下运行 java文件 Math ,String ,Scanner,Interger等常用类的使用 jdk,jre,jvm等概念的了解 classpath, ...
- 201521123116 《java程序设计》第十三周学习总结
1. 本周学习总结 以你喜欢的方式(思维导图.OneNote或其他)归纳总结多网络相关内容. 2. 书面作业 Q1. 网络基础 1.1 比较ping www.baidu.com与ping cec.jm ...
- 201521123121 《Java程序设计》第13周学习总结
1. 本周学习总结 以你喜欢的方式(思维导图.OneNote或其他)归纳总结多网络相关内容. 1.两类传输协议:TCP:UDP TCP/IP协议的名称中只有TCP这个协议名,但是在TCP/IP的传输层 ...
- linux segmentation fault记录
文章将记录linux学习使用中出现的各种segmentation fault,持续更新,希望对看到人有所帮助 1. linux pcap segmentation fault -- 2013.11.2 ...
- thymeleaf模板引擎调用java类中的方法(附源码)
前言 <Docker+SpringBoot+Mybatis+thymeleaf的Java博客系统开源啦> 由于开源了项目的缘故,很多使用了My Blog项目的朋友遇到问题也都会联系我去解决 ...
- 《MySQL必知必会》[03] 表数据的增删改
1.增:插入数据 INSERT关键字可以插入新的行到数据库表中: 插入完整的行 插入行的一部分 插入多行 插入某些查询的结果 基本的INSERT语句是: INSERT INTO R(A1, A2, . ...