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. PyCharm:2017.3版即将新增科学计算模式,预览版现在可以下载使用

    编译:Lemon,原文作者:Ernst Haagsman 公众号:Python数据之道(ID:PyDataRoad) pycharm:2017.3版即将新增科学计算模式 在JetBrains将发布的新 ...

  2. shell下office、html、pdf文档互转方法

     分类: 后台开发 版权声明:本文为博主原创文章,未经博主允许不得转载.   OFFICE 文档在线预览方案很多: 服务器先转换为PDF,再转换为SWF,最后通过网页加载Flash预览,比如flexp ...

  3. html5中的video标签和audio标签

    不管是否承认,flash早已不像过往那样如日中天了.亚马逊全面放弃flash.苹果放弃flash.安卓也放弃了移动端的flash支持.事实上flash已经不太适合web开发了,因为HTML5中的vid ...

  4. 转: 【Java并发编程】之三:线程挂起、恢复与终止的正确方法(含代码)

    转载请注明出处:http://blog.csdn.net/ns_code/article/details/17095733 挂起和恢复线程     Thread 的API中包含两个被淘汰的方法,它们用 ...

  5. 转:【深入Java虚拟机】之五:多态性实现机制——静态分派与动态分派

    转载请注明出处:http://blog.csdn.net/ns_code/article/details/17965867   方法解析 Class文件的编译过程中不包含传统编译中的连接步骤,一切方法 ...

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

    1. 本周学习总结 1.1 尝试使用思维导图总结有关继承的知识点. 1.2 使用常规方法总结其他上课内容. (1)继承:子类继承父类,子类可以复用父类的方法和函数. (2)多态:方法的重写和重载是Ja ...

  7. 201521123054《Java程序设计》第4周总结

    1. 本周学习总结 2. 书面作业 注释的应用 使用类的注释与方法的注释为前面编写的类与方法进行注释,并在Eclipse中查看.(截图) 面向对象设计(大作业1,非常重要) **2.1 将在网上商城购 ...

  8. JAVA课程设计 刘舒婷 201521123096

    1.团队课程设计博客链接 2.个人负责模块说明 2.1 界面菜单的设计: 2.2 录入学生信息: 2.3 对已录入的学生信息进行修改: 3.个人代码提交记录截图 4.自己负责模块或任务详细说明 4.1 ...

  9. 201521123119 《Java程序设计》第13周学习总结

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

  10. 笔记2 linux多线程 读写锁

    //read write lock #include<stdio.h> #include<unistd.h> #include<pthread.h> struct ...