concurrenthashmap

ConcurrentHashMap

匿名 (未验证) 提交于 2019-12-02 23:55:01
ConcurrentHashMap主要有三大结构:整个Hash表,segment(段),HashEntry(节点)。每个segment就相当于一个HashTable。 Base 1.8 抛弃了原有的 Segment 分段锁,而采用了 CAS + synchronized 来保证并发安全性。 (1)HashEntry类 每个HashEntry代表Hash表中的一个节点,在其定义的结构中可以看到,除了value值没有定义final,其余的都定义为final类型,我们知道Java中关键词final修饰的域成为最终域。用关键词final修饰的变量一旦赋值,就不能改变,也称为修饰的标识为常量。这就意味着我们删除或者增加一个节点的时候,就必须从头开始重新建立Hash链,因为next引用值需要改变。 (2)segment类 Segment 类继承于 ReentrantLock 类,从而使得 Segment 对象能充当锁的角色。每个 Segment 对象用来守护其(成员对象 table 中)包含的若干个桶。   table 是一个由 HashEntry 对象组成的数组。table 数组的每一个数组成员就是散列映射表的一个桶。   count 变量是一个计数器,它表示每个 Segment 对象管理的 table 数组(若干个 HashEntry 组成的链表)包含的 HashEntry 对象的个数

为什么juc下的集合类是线程安全的的

匿名 (未验证) 提交于 2019-12-02 23:49:02
也有一些线程安全的集合,如Vector,HashTable,但大多都是基于sychronized锁控制机制,性能很低。 如果既保证线程安全,执行效率又高,就可考虑下JUC下的集合类了,如: ArrayList对应的高并发类是CopyOnWriteArrayList, HashMap对应的高并发类是ConcurrentHashMap。 它们鱼与熊掌可兼得。但它们为什么在保证效率的同时还能保证线程安全呢? 那么我们先来看看CopyOnWriteArrayList。 CopyOnWriteArrayList提供高效地读取操作,使用在读多写少的场景。CopyOnWriteArrayList读取操作不用加锁,且是安全的; 写操作时,先copy一份原有数据数组,再对复制数据进行写入操作,最后将复制数据替换原有数据,从而保证写操作不影响读操作。 同时注意:其copy的整个过程是上了锁的,所以不会产生多线程安全问题。 我们来看看CopyOnWriteArrayList的核心的源码: /** * Appends the specified element to the end of this list. * * @param e element to be appended to this list * @return {@code true} (as specified by {@link

ConcurrentHashMap 原理解析(JDK1.8)

匿名 (未验证) 提交于 2019-12-02 23:35:02
了解ConcurrentHashMap 实现原理,建议首先了解下 HashMap 实现原理。 HashMap 源码解析(JDK1.8) 为什么要用ConcurrentHashMap HashMap线程不安全,而Hashtable是线程安全,但是它使用了synchronized进行方法同步,插入、读取数据都使用了synchronized,当插入数据的时候不能进行读取(相当于把整个Hashtable都锁住了,全表锁),当多线程并发的情况下,都要竞争同一把锁,导致效率极其低下。而在JDK1.5后为了改进Hashtable的痛点,ConcurrentHashMap应运而生。 ConcurrentHashMap为什么高效? JDK1.5中的实现 ConcurrentHashMap使用的是分段锁技术,将ConcurrentHashMap将锁一段一段的存储,然后给每一段数据配一把锁(segment),当一个线程占用一把锁(segment)访问其中一段数据的时候,其他段的数据也能被其它的线程访问,默认分配16个segment。默认比Hashtable效率提高16倍。 ConcurrentHashMap的结构图如下(网友贡献的图,哈): Paste_Image.png JDK1.8中的实现 ConcurrentHashMap取消了segment分段锁

HashMap与ConcurrentHashMap 详解

匿名 (未验证) 提交于 2019-12-02 22:56:40
本文分析了HashMap的实现原理,以及resize可能引起死循环和Fast-fail等线程不安全行为。同时结合源码从数据结构,寻址方式,同步方式,计算size等角度分析了JDK 1.7和JDK 1.8中ConcurrentHashMap的实现原理。 原创文章,转载请务必将下面这段话置于文章开头处(保留超链接)。 本文转发自 技术世界 , 原文链接   http://www.jasongj.com/java/concurrenthashmap/ 众所周知,HashMap是非线程安全的。而HashMap的线程不安全主要体现在resize时的死循环及使用迭代器时的fast-fail上。 注:本章的代码均基于JDK 1.7.0_67 常用的底层数据结构主要有数组和链表。数组存储区间连续,占用内存较多,寻址容易,插入和删除困难。链表存储区间离散,占用内存较少,寻址困难,插入和删除容易。 HashMap要实现的是哈希表的效果,尽量实现O(1)级别的增删改查。它的具体实现则是同时使用了数组和链表,可以认为最外层是一个数组,数组的每个元素是一个链表的表头。 对于新插入的数据或者待读取的数据,HashMap将Key的哈希值对数组长度取模,结果作为该Entry在数组中的index。在计算机中,取模的代价远高于位操作的代价,因此HashMap要求数组的长度必须为2的N次方。此时将Key的哈希值对2^N

Java 初/中级面试题及答案【详细】

匿名 (未验证) 提交于 2019-12-02 21:53:52
更多Java 面试笔试系列文章: 1.Java的HashMap是如何工作的? HashMap是一个针对数据结构的键值,每个键都会有相应的值,关键是识别这样的值。 HashMap 基于 hashing 原理,我们通过 put ()和 get ()方法储存和获取对象。当我们将键值对传递给 put ()方法时,它调用键对象的 hashCode ()方法来计算 hashcode,让后找到 bucket 位置来储存值对象。当获取对象时,通过键对象的 equals ()方法找到正确的键值对,然后返回值对象。HashMap 使用 LinkedList 来解决碰撞问题,当发生碰撞了,对象将会储存在 LinkedList 的下一个节点中。 HashMap 在每个 LinkedList 节点中储存键值对对象。 参考: 浅谈Java中的hashcode方法 集合系列―HashMap源码分析 2.什么是快速失败的故障安全迭代器? 快速失败的Java迭代器可能会引发ConcurrentModifcationException在底层集合迭代过程中被修改。故障安全作为发生在实例中的一个副本迭代是不会抛出任何异常的。快速失败的故障安全范例定义了当遭遇故障时系统是如何反应的。例如,用于失败的快速迭代器ArrayList和用于故障安全的迭代器ConcurrentHashMap。 3.Java

Java集合之ConcurrentHashMap

匿名 (未验证) 提交于 2019-12-02 21:53:52
本文转载自 dreamcatcher-cx 作者,出处: ConcurrentHashMap实现原理及源码分析 ConcurrentHashMap是Java并发包中提供的一个线程安全且高效的HashMap实现,ConcurrentHashMap在并发编程的场景中使用频率非常之高,本文就来分析下ConcurrentHashMap的实现原理,并对其实现原理进行分析(JDK1.7). JDK1.8之前ConcurrentHashMap采用的分段锁,JDK1.8之后采用CAS算法(不做分析) 先来看看ConcurrentHashMap是个啥结构。 在JDK1.7中,ConcurrentHashMap的数据结构是由一个Segment数组和多个HashEntry组成,结构如下图所示: 众所周知,哈希表是中非常高效,复杂度为O(1)的数据结构,在Java开发中,我们最常见到最频繁使用的就是HashMap和HashTable,但是在线程竞争激烈的并发场景中使用都不够合理。    HashMap :先说HashMap,HashMap是 线程不安全 的,在并发环境下,可能会形成环 状链表 (扩容时可能造成,具体原因自行百度google或查看源码分析),导致get操作时,cpu空转,所以,在并发环境中使用HashMap是非常危险的。    HashTable :

【Java并发编程】23、ConcurrentHashMap原理分析(1.7和1.8版本对比)

匿名 (未验证) 提交于 2019-12-02 21:53:32
jdk 1.8版本 ConcurrentHashMap在1.8中的实现,相比于1.7的版本基本上全部都变掉了。首先,取消了Segment分段锁的数据结构,取而代之的是数组+链表(红黑树)的结构。而对于锁的粒度,调整为对每个数组元素加锁(Node)。 put的步骤大致如下: 参数校验。 若table[]未创建,则初始化。table的初始化和扩容采用CAS无锁设计,通过状态 sizeCtl 来控制线程的并发操作:U.compareAndSwapInt(this, SIZECTL, sc, -1) 当table[i]后面无节点时,直接创建Node(无锁操作)。也是通过CAS实现:return U.compareAndSwapObject(tab, ((long)i << ASHIFT) + ABASE, c, v); 如果当前正在扩容,则帮助扩容并返回最新table[]。 然后在链表或者红黑树中追加节点。此过程通过 如果是链表,遍历链表,发现相同key则替换旧值,没有发现相同key则添加到链表的末尾 如果是红黑树, 最后还回去判断是否到达阀值,如到达变为红黑树结构。使用方法:treeifyBin(tab, i); 首先定位到table[]中的i。 若table[i]存在,则继续查找。 首先比较链表头部,如果是则返回。 然后如果为红黑树,查找树。 如果不是红黑树,循环链表查找。

concurrentHashMap实现原理

送分小仙女□ 提交于 2019-12-02 19:11:57
JDK6与JDK7中的实现: 理解concurrentHashMap首先最关键先理解一个概念:segment segment是什么呢?segment本身就相当于一个HashMap对象,同时又继承了ReentrantLock;同HashMap一样,segment包含一个HashEntry数组,数组的每一个HashEntry既是一个键值对,也是一个链表的头节点;HashEntry中的value和next都被volatile修饰,用于多线程保证可见性。 像这样的segment对象,在concurrentHashMap中集合中有2的N次方个,共同保存在一个名为segments的数组当中。 因此整个ConcurrentHashMap的结构如下: concurrentHashMap是在一个总的哈希表下面,有若干个子哈希表。这样的二级结构,数据库的水平拆分有些相似。 这样设计的优势在于:才用了锁分段技术,每一个segment就好比一个自治区,读写操作高度自治,segment之间互不影响。 不同segment的写入可以并发执行,同一个segment的读写可以并发执行,同一个segment的并发写会被阻塞。由此可见,concurrentHashMap当中每个segment各自持有一把锁。在保证线程安全的同时降低了锁的粒度,让并发操作效率更高。 ConcurrentHashMap的读写详细过程:

Counting the number of exceptions happening in catch block

亡梦爱人 提交于 2019-12-02 12:40:10
问题 I am trying to collect all the counts of exception happening and the name of exception in a ConcurrentHashMap so that I should be aware of how many times this exception has occurred. So in my catch block I have map that will keep on adding the name of exception and there total count occurrence. Below is my code which I have modified to always throw SQL Exception everytime for the testing purpose so that I can see the count of exception is accurate or not. So certain scenario- 1) If I am

深入理解HashMap和CurrentHashMap

懵懂的女人 提交于 2019-12-02 09:30:11
原文链接: https://segmentfault.com/a/1190000015726870 前言 Map 这样的 Key Value 在软件开发中是非常经典的结构,常用于在内存中存放数据。 本篇主要想讨论 ConcurrentHashMap 这样一个并发容器,在正式开始之前我觉得有必要谈谈 HashMap,没有它就不会有后面的 ConcurrentHashMap。 HashMap 众所周知 HashMap 底层是基于 数组 + 链表 组成的,不过在 jdk1.7 和 1.8 中具体实现稍有不同。 Base 1.7 1.7 中的数据结构图: 先来看看 1.7 中的实现。 这是 HashMap 中比较核心的几个成员变量;看看分别是什么意思? 初始化桶大小,因为底层是数组,所以这是数组默认的大小。 桶最大值。 默认的负载因子(0.75) table 真正存放数据的数组。 Map 存放数量的大小。 桶大小,可在初始化时显式指定。 负载因子,可在初始化时显式指定。 重点解释下负载因子: 由于给定的 HashMap 的容量大小是固定的,比如默认初始化: 1 public HashMap() { 2 this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR); 3 } 4 5 public HashMap(int initialCapacity