ConcurrentHashMap1.7源码分析
参考:https://www.cnblogs.com/liuyun1995/p/8631264.html
HashMap不是线程安全的,其所有的方法都未同步,虽然可以使用Collections的synchronizedMap方法使其线程安全,但是针对的只是当前的map对象。对此,
JDK提供了线程安全的Hashtable,其所有的方法都是同步的,即使用Synchronized关键字进行加锁,但是也导致了同一时刻只能有一个线程操作哈希表,影响
性能,所以又提供了效率较高的线程安全的哈希表ConcurrentHashMap,其内部使用分段锁将锁进行细粒度化,从而使多个线程能够同时操作哈希表,大大提
高了性能。下面是其内部结构示意图:

Like {@link Hashtable} but unlike {@link HashMap}, this class
does <em>not</em> allow {@code null} to be used as a key or value
和Hashtable一样,不允许null键和null值
Concurrent1.7和1.8的区别:
1.7中采用Segment+HashEntry的方式进行实现,并发控制使用ReentrantLock来实现。
每一个Segment元素存储的是HashEntry数组+链表,和HashMap的数据结构相同
1.8中放弃了Segment臃肿的设计,取而代之的是采用Node数组+链表+红黑树的数据结构来实现,当链表的长度大于8时会转化为红黑树。
并发控制使用 Synchronized+CAS来保证
JDK1.8版本的ConcurrentHashMap的数据结构已经接近HashMap,相对而言,ConcurrentHashMap只是增加了同步的操作来控制并发,从JDK1.7版本的ReentrantLock+Segment+HashEntry,到JDK1.8版本中synchronized+CAS+HashEntry+红黑树,相对而言,总结如下思考
JDK1.8的实现降低锁的粒度,JDK1.7版本锁的粒度是基于Segment的,包含多个HashEntry,而JDK1.8锁的粒度就是HashEntry(首节点)
JDK1.8版本的数据结构变得更加简单,使得操作也更加清晰流畅,因为已经使用synchronized来进行同步,所以不需要分段锁的概念,也就不需要Segment这种数据结构了,由于粒度的降低,实现的复杂度也增加了
JDK1.8使用红黑树来优化链表,基于长度很长的链表的遍历是一个很漫长的过程,而红黑树的遍历效率是很快的(logn),代替一定阈值的链表,这样形成一个最佳拍档
JDK1.8为什么使用内置锁synchronized来代替重入锁ReentrantLock:
1、因为粒度降低了,在相对而言的低粒度加锁方式,synchronized并不比ReentrantLock差,在粗粒度加锁中ReentrantLock可能通过Condition来控制各个低粒度的边界,
更加的灵活,而在低粒度中,Condition的优势就没有了
2、JVM的开发团队从来都没有放弃synchronized,而且基于JVM的synchronized优化空间更大,使用内嵌的关键字比使用API更加自然
3、在大量的数据操作下,对于JVM的内存压力,基于API的ReentrantLock会开销更多的内存,虽然不是瓶颈,但是也是一个选择依据
原文:https://blog.csdn.net/qq296398300/article/details/79074239
以下源码基于Java 1.7版本
public class ConcurrentHashMap<K, V> extends AbstractMap<K, V>
implements ConcurrentMap<K, V>, Serializable {
private static final long serialVersionUID = 7249069246763182397L;
其成员变量:
/**
* The maximum number of segments to allow; used to bound
* constructor arguments. Must be power of two less than 1 << 24.
* 分段锁的最大数量
*/
static final int MAX_SEGMENTS = 1 << 16; /**
* Number of unsynchronized retries in size and containsValue
* methods before resorting to locking. This is used to avoid
* unbounded retries if tables undergo continuous modification
* which would make it impossible to obtain an accurate result.
* 分段锁的最小数量
*/
static final int RETRIES_BEFORE_LOCK = 2;
/**
* Mask value for indexing into segments. The upper bits of a
* key's hash code are used to choose the segment.
* 分段锁的掩码值
*/
final int segmentMask; /**
* Shift value for indexing within segments.
* 分段锁的移位值
*/
final int segmentShift; /**
* The segments, each of which is a specialized hash table.
* 分段锁数组
*/
final Segment<K,V>[] segments;
Segment是ConcurrentHashpMap的一个静态内部类:
static final class Segment<K,V> extends ReentrantLock implements Serializable {
static final int MAX_SCAN_RETRIES =
Runtime.getRuntime().availableProcessors() > 1 ? 64 : 1;
transient volatile HashEntry<K,V>[] table;
transient int count;
transient int modCount;
transient int threshold;
final float loadFactor;
Segment继承了ReentrantLock ,所以其本质上是一个锁。
分段锁即是由Segment来实现的,它继承于ReentrantLock,用来管理它辖区内的各个HashEntry。ConcurrentHashMap被Segment分成了很多小区,Segment就相当于小区保安,
HashEntry列表相当于小区业主,小区保安通过加锁的方式,保证每个Segment内都不发生冲突。
put和remove方法,对于Segment内部元素和计数器的更新,全部处于锁的保护下,如Segment.put()方法的第一行:
HashEntry<K,V> node = tryLock() ? null : scanAndLockForPut(key, hash, value);
ConcurrentHashMap1.7源码分析的更多相关文章
- ConcurrentHashMap1.8源码分析
文章简介 想必大家对HashMap数据结构并不陌生,JDK1.7采用的是数组+链表的方式,JDK1.8采用的是数组+链表+红黑树的方式.虽然JDK1.8对于HashMap有了很大的改进,提高了存取效率 ...
- ABP源码分析一:整体项目结构及目录
ABP是一套非常优秀的web应用程序架构,适合用来搭建集中式架构的web应用程序. 整个Abp的Infrastructure是以Abp这个package为核心模块(core)+15个模块(module ...
- HashMap与TreeMap源码分析
1. 引言 在红黑树--算法导论(15)中学习了红黑树的原理.本来打算自己来试着实现一下,然而在看了JDK(1.8.0)TreeMap的源码后恍然发现原来它就是利用红黑树实现的(很惭愧学了Ja ...
- nginx源码分析之网络初始化
nginx作为一个高性能的HTTP服务器,网络的处理是其核心,了解网络的初始化有助于加深对nginx网络处理的了解,本文主要通过nginx的源代码来分析其网络初始化. 从配置文件中读取初始化信息 与网 ...
- zookeeper源码分析之五服务端(集群leader)处理请求流程
leader的实现类为LeaderZooKeeperServer,它间接继承自标准ZookeeperServer.它规定了请求到达leader时需要经历的路径: PrepRequestProcesso ...
- zookeeper源码分析之四服务端(单机)处理请求流程
上文: zookeeper源码分析之一服务端启动过程 中,我们介绍了zookeeper服务器的启动过程,其中单机是ZookeeperServer启动,集群使用QuorumPeer启动,那么这次我们分析 ...
- zookeeper源码分析之三客户端发送请求流程
znode 可以被监控,包括这个目录节点中存储的数据的修改,子节点目录的变化等,一旦变化可以通知设置监控的客户端,这个功能是zookeeper对于应用最重要的特性,通过这个特性可以实现的功能包括配置的 ...
- java使用websocket,并且获取HttpSession,源码分析
转载请在页首注明作者与出处 http://www.cnblogs.com/zhuxiaojie/p/6238826.html 一:本文使用范围 此文不仅仅局限于spring boot,普通的sprin ...
- ABP源码分析二:ABP中配置的注册和初始化
一般来说,ASP.NET Web应用程序的第一个执行的方法是Global.asax下定义的Start方法.执行这个方法前HttpApplication 实例必须存在,也就是说其构造函数的执行必然是完成 ...
随机推荐
- 10 Advanced Bing Search Tricks You Should Know
Exclude Websites From Bing Search: wikipedia -wikipedia.org Excluding Keywords From Bing Search: fac ...
- EZOJ #374学习
分析 二分天数 暴力判断即可 代码 #include<bits/stdc++.h> using namespace std; #define int long long ],b[],c[] ...
- leetcode 148. 排序链表(c++)
在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序. 示例 1: 输入: 4->2->1->3输出: 1->2->3->4示例 2: 输入: ...
- css设计丝带
<!DOCTYPE html><html lang="zh-CN"><head><meta charset="UTF-8&quo ...
- _exit和exit的区别
在linux的标准库函数中,有一套称作高级I/O的函数,我们熟知的printf .fopen .fread .fwrite都在此列,他们也被称作缓冲I/O.其特征是对应每一个打开的文件,都存在一个缓冲 ...
- hihocoder 1015 : KMP算法(kmp)
传送门 Description 小Hi和小Ho是一对好朋友,出生在信息化社会的他们对编程产生了莫大的兴趣,他们约定好互相帮助,在编程的学习道路上一同前进. 这一天,他们遇到了一只河蟹,于是河蟹就向小H ...
- Web控件LinkButton
<asp:LinkButton ID="" runat="server" ></asp:LinkButton> 编译后就变成了回发事件 ...
- vue手写轮播
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- 虚拟机环境搭建/修改VMware虚拟机固定IP
VMware Workstation安装CentOS7.0 详情教程: centos7.0下载地址:http://isoredirect.centos.org/centos/7/isos/x86_64 ...
- CentOS利用Lua访问Redis
首先确保你编译的Lua是支持链接外部动态链接库的.因为在对Redis进行访问时是需要使用socket通信的, 而这依赖于外部的C语言写的动态连接库. 首先,这里先下载Redis的Lua客户端访问包re ...