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源码及分析的更多相关文章

  1. Hashtable、ConcurrentHashMap源码分析

    Hashtable.ConcurrentHashMap源码分析 为什么把这两个数据结构对比分析呢,相信大家都明白.首先二者都是线程安全的,但是二者保证线程安全的方式却是不同的.废话不多说了,从源码的角 ...

  2. ConcurrentHashMap源码分析(一)

    本篇博客的目录: 前言 一:ConcurrentHashMap简介 二:ConcurrentHashMap的内部实现 三:总结 前言:HashMap很多人都熟悉吧,它是我们平时编程中高频率出现的一种集 ...

  3. ConcurrentHashMap 源码分析

    ConcurrentHashMap 源码分析 1. 前言    终于到这个类了,其实在前面很过很多次这个类,因为这个类代码量比较大,并且涉及到并发的问题,还有一点就是这个代码有些真的晦涩,不好懂.前前 ...

  4. 死磕 java集合之ConcurrentHashMap源码分析(三)

    本章接着上两章,链接直达: 死磕 java集合之ConcurrentHashMap源码分析(一) 死磕 java集合之ConcurrentHashMap源码分析(二) 删除元素 删除元素跟添加元素一样 ...

  5. JDK(十)JDK1.7&1.8源码对比分析【集合】ConcurrentHashMap

    前言 在JDK1.7&1.8源码对比分析[集合]HashMap中我们对比分析了JDK1.7和1.8版本的HashMap源码,趁热打铁,这篇文章就来看看JDK1.7和1.8版本的Concurre ...

  6. 并发-ConcurrentHashMap源码分析

    ConcurrentHashMap 参考: http://www.cnblogs.com/chengxiao/p/6842045.html https://my.oschina.net/hosee/b ...

  7. JDK1.7 ConcurrentHashMap 源码浅析

    概述 ConcurrentHashMap是HashMap的线程安全版本,使用了分段加锁的方案,在高并发时有比较好的性能. 本文分析JDK1.7中ConcurrentHashMap的实现. 正文 Con ...

  8. HashMap 与 ConcrrentHashMap 使用以及源码原理分析

    前奏一:HashMap面试中常见问题汇总 HashMap的工作原理是近年来常见的Java面试题,几乎每个Java程序员都知道HashMap,都知道哪里要用HashMap,知道HashTable和Has ...

  9. JDK12 concurrenthashmap源码阅读

           本文部分照片和代码分析来自文末参考资料        java8中的concurrenthashmap的方法逻辑和注解有些问题,建议看最新的JDK版本        建议阅读 concu ...

随机推荐

  1. [[NSBundle mainBundle] pathForResource:fileName ofType:]获取文件路径不成功

    目标文件明明已经加入项目了,但是使用[[NSBundle mainBundle] pathForResource:fileName ofType:]来获取文件路径的时候却为nil: 遇到这个问题大家需 ...

  2. MySQL(一) -- MySQL学习路线、数据库的基础、关系型数据库、关键字说明、SQL、MySQL数据库、MySQL服务器对象、SQL的基本操作、库操作、表操作、数据操作、中文数据问题、 校对集问题、web乱码问题

    1 MySQL学习路线 基础阶段:MySQL数据库的基本操作(增删改查),以及一些高级操作(视图.触发器.函数.存储过程等). 优化阶段:如何提高数据库的效率,如索引,分表等. 部署阶段:如何搭建真实 ...

  3. 《深入浅出MySQL》之数据类型

    MySQL提供了多种数据类型,主要包括数值型.字符串型和日期时间类型.本次博客就来谈谈MySQL中常用的数据类型吧(版本:mysql-5.7.19)! 数值类型 MySQL支持所有标准SQL中数值类型 ...

  4. 团队作业8——Beta 阶段冲刺5th day

    一.当天站立式会议 二.每个人的工作 (1)昨天已完成的工作(具体在表格中) 支付功能测试 (2)今天计划完成的工作(具体如下) 完善订单功能 (3)工作中遇到的困难(在表格中) 成员 昨天已完成的工 ...

  5. 201521123068《Java程序设计》第6周学习总结

    1. 本周学习总结 1.1 面向对象学习暂告一段落,请使用思维导图,以封装.继承.多态为核心概念画一张思维导图,对面向对象思想进行一个总结. 点击->面向对象学习 2. 书面作业 1.clone ...

  6. 201521123069 《Java程序设计》 第4周学习总结

    1. 本周学习总结 1.1 尝试使用思维导图总结有关继承的知识点. 1.2 使用常规方法总结其他上课内容. (1)文档注释(类注释.方法注释.属性注释.通用注释.) (2)多态性.instanceof ...

  7. 201521123023《java程序设计》第四周学习总结

    1. 本周学习总结 思维导图 常规: (1)抽象类:不能被直接实例化.只能作为其它类的父类,这一点与final类正好相反.用关键词abstract声明. (2)继承:只能有一个父类,即单继承,子类继承 ...

  8. 201521123056 《Java程序设计》第3周学习总结

    1. 本周学习总结 -本周学习了面向对象,学会了如何用Eclipse自动生成setter/getter/toString以及构造有参函数等 2. 书面作业 1.代码阅读 public class Te ...

  9. 201521123008<java程序设计>第三周实验总结

    1.本周学习总结 2.书面作业 1.代码阅读 public class Test1 { private int i = 1;//这行不能修改 private static int j = 2; pub ...

  10. 201521123066《Java程序设计》第十三周学习总结

    1. 本周学习总结 以你喜欢的方式(思维导图.OneNote或其他)归纳总结多网络相关内容. 2. 书面作业 1. 网络基础 1.1 比较ping www.baidu.com与ping cec.jmu ...