ConcurrentHashMap学习
来源:互联网 发布:融资毕业论文知乎 编辑:程序博客网 时间:2024/09/21 09:22
ConcurrentHashMap
原文章:http://www.iteye.com/topic/344876
实现原理:
锁分离 (Lock Stripping)
ConcurrentHashMap允许多个修改操作并发进行,其关键在于使用了锁分离技术。它使用了多个锁来控制对hash表的不同部分进行的修改。ConcurrentHashMap内部使用段(Segment)来表示这些不同的部分,每个段其实就是一个小的hash table,它们有自己的锁。只要多个修改操作发生在不同的段上,它们就可以并发进行。
<span style="white-space:pre"></span>final Segment<K,V>[] segments;
有些方法需要跨段,比如size()和containsValue(),它们可能需要锁定整个表而而不仅仅是某个段,这需要按顺序锁定所有段,操作完毕后,又按顺序释放所有段的锁。这里“按顺序”是很重要的,否则极有可能出现死锁,在ConcurrentHashMap内部,段数组是final的,并且其成员变量实际上也是final的,但是,仅仅是将数组声明为final的并不保证数组成员也是final的,这需要实现上的保证。这可以确保不会出现死锁,因为获得锁的顺序是固定的。不变性是多线程编程占有很重要的地位,下面还要谈到。
不变(Immutable)和易变(Volatile)
ConcurrentHashMap完全允许多个读操作并发进行,读操作并不需要加锁。如果使用传统的技术,如HashMap中的实现,如果允许可以在hash链的中间添加或删除元素,读操作不加锁将得到不一致的数据。ConcurrentHashMap实现技术是保证HashEntry几乎是不可变的。HashEntry代表每个hash链中的一个节点,其结构如下所示:
static final class HashEntry<K,V> { final K key; final int hash; volatile V value; final HashEntry<K,V> next; }可以看到除了value不是final的,其它值都是final的,这意味着不能从hash链的中间或尾部添加或删除节点,因为这需要修改next引用值,所有的节点的修改只能从头部开始。对于put操作,可以一律添加到Hash链的头部。但是对于remove操作,可能需要从中间删除一个节点,这就需要将要删除节点的前面所有节点整个复制一遍,最后一个节点指向要删除结点的下一个结点。这在讲解删除操作时还会详述。为了确保读操作能够看到最新的值,将value设置成volatile,这避免了加锁。
数据结构
Hash表的一个很重要方面就是如何解决hash冲突,ConcurrentHashMap和HashMap使用相同的方式,都是将hash值相同的节点放在一个hash链中。与HashMap不同的是,ConcurrentHashMap使用多个子Hash表,也就是段(Segment)。下面是ConcurrentHashMap的数据成员:
public class ConcurrentHashMap<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V>, Serializable { private static final long serialVersionUID = 7249069246763182397L;
/** * 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;final的成员,其中segmentMask和segmentShift主要是为了定位段,参见上面的segmentFor方法。每个Segment相当于一个子Hash表,它的数据成员如下:
static final class Segment<K,V> extends ReentrantLock implements Serializable {
<span style="white-space:pre"></span>/** * The per-segment table. Elements are accessed via * entryAt/setEntryAt providing volatile semantics. */ transient volatile HashEntry<K,V>[] table;
<span style="white-space:pre"></span>/** * The number of elements. Accessed only either within locks * or among other volatile reads that maintain visibility. */ transient int count;
<pre name="code" class="java"> /** * The total number of mutative operations in this segment. * Even though this may overflows 32 bits, it provides * sufficient accuracy for stability checks in CHM isEmpty() * and size() methods. Accessed only either within locks or * among other volatile reads that maintain visibility. */ transient int modCount;
/** * The table is rehashed when its size exceeds this threshold. * (The value of this field is always <tt>(int)(capacity * * loadFactor)</tt>.) */ transient int threshold;
/** * The load factor for the hash table. Even though this value * is same for all segments, it is replicated to avoid needing * links to outer object. * @serial */ final float loadFactor;count用来统计该段数据的个数,它是volatile,它用来协调修改和读取操作,以保证读取操作能够读取到几乎最新的修改。
协调方式是这样的,每次修改操作做了结构上的改变,如增加/删除节点(修改节点的值不算结构上的改变),都要写count值,每次读取操作开始都要读取count的值。这利用了Java 5中对volatile语义的增强,对同一个volatile变量的写和读存在happens-before关系。modCount统计段结构改变的次数,主要是为了检测对多个段进行遍历过程中某个段是否发生改变,在讲述跨段操作时会还会详述。threashold用来表示需要进行rehash的界限值。table数组存储段中节点,每个数组元素是个hash链,用HashEntry表示。table也是volatile,这使得能够读取到最新的table值而不需要同步。loadFactor表示负载因子
0 0
- ConcurrentHashMap学习
- ConcurrentHashMap学习
- Java中ConcurrentHashMap学习
- Java中ConcurrentHashMap学习
- concurrentHashMap原理学习
- Java中ConcurrentHashMap学习
- Java中ConcurrentHashMap学习
- Java中ConcurrentHashMap学习
- JDK8 ConcurrentHashMap学习
- concurrentHashMap学习(一)
- concurrentHashMap学习(二)
- concurrentHashMap学习(三)
- concurrentHashMap学习(四)
- ConcurrentHashMap学习笔记(Java8)
- 深入学习ConcurrentHashMap
- Hashtable 、ConcurrentHashMap源码学习
- ConcurrentHashMap学习笔记一
- ConcurrentHashMap学习总结
- caffe基础(7): 命令行解析
- C#中的async与await
- 正对Fragment Transaction BackStack的误解
- struts2的核心和工作原理
- iOS饼状图实现
- ConcurrentHashMap学习
- OPatch cannot process overlay patches because of no OUI support
- Android初尝甜果之MVP模式
- 没有文采”的人 怎么才能写出干货?
- 解决编译Tensorflow serving 时无法访问googlesource中的boringssl的问题
- Cocos2d-x初入学堂(10)-->ParticleEditor粒子编辑器
- iOS开发--- UIScrollView属性以及代理大全
- eclipse使用非系统默认JDK
- java调整日期时间显示格式