ConcurrentHashMap
来源:互联网 发布:安卓手机游戏源码 编辑:程序博客网 时间:2024/06/05 22:42
ConcurrentHashMap
1.实现原理
2.数据结构
3.增删改查
一.实现原理
锁分离
ConcurrentHashMap使用分段锁技术,将数据分段存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据的时候,
其他段的数据也能被其他线程访问,能够实现真正的并发访问。
对于一个key,需要经过三次(为什么要hash三次下文会详细讲解)hash操作,才能最终定位这个元素的位置,这三次hash分别为:
对于一个key,先进行一次hash操作,得到hash值h1,也即h1 = hash1(key);
将得到的h1的高几位进行第二次hash,得到hash值h2,也即h2 = hash2(h1高几位),通过h2能够确定该元素的放在哪个Segment;
将得到的h1进行第三次hash,得到hash值h3,也即h3 = hash3(h1),通过h3能够确定该元素放置在哪个HashEntry。
除了value不是final的,其它值都是final的,因此所有的节点的修改只能从头部开始
三.增删改查
remove
1.定位到segment
2.加锁
3.定位到要删除的数据
put
1.通过hash算法得到对应的分段
2.向分段中push值
3.判断是否需要rehash
4.修改modcount
5.插入值,一律添加到Hash链的头部。
6.修改count
get
1.定位到segment
2.阅读count,保证happens_before(不是绝对安全)
3.获得值
4.如果为空则加锁重新读
size
1.先给3次机会,不lock所有的Segment,遍历所有Segment,累加各个Segment的大小得到整个Map的大小,
如果某相邻的两次计算获取的所有Segment的更新的次数(每个Segment都有一个modCount变量,
这个变量在Segment中的Entry被修改时会加一,通过这个值可以得到每个Segment的更新操作的次数)是一样的,
说明计算过程中没有更新操作,则直接返回这个值。
2.如果这三次不加锁的计算过程中Map的更新次数有变化,则之后的计算先对所有的Segment加锁,再遍历所有Segment计算Map大小,最后再解锁所有Segment
1.实现原理
2.数据结构
3.增删改查
一.实现原理
锁分离
ConcurrentHashMap使用分段锁技术,将数据分段存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据的时候,
其他段的数据也能被其他线程访问,能够实现真正的并发访问。
对于一个key,需要经过三次(为什么要hash三次下文会详细讲解)hash操作,才能最终定位这个元素的位置,这三次hash分别为:
对于一个key,先进行一次hash操作,得到hash值h1,也即h1 = hash1(key);
将得到的h1的高几位进行第二次hash,得到hash值h2,也即h2 = hash2(h1高几位),通过h2能够确定该元素的放在哪个Segment;
将得到的h1进行第三次hash,得到hash值h3,也即h3 = hash3(h1),通过h3能够确定该元素放置在哪个HashEntry。
二.数据结构
public class ConcurrentHashMap<K, V> { final int segmentMask; // 段掩码 等于数组长度-1 默认为15 final int segmentShift; // 段偏移量 等于 32 - 数组长度从1向左移位的次数, 长度默认为16所以默认为32-4=28 final Segment<K,V>[] segments;}static final class Segment<K,V> extends ReentrantLock{ transient volatile int count; // 统计该段数据的个数 transient int modCount; // 统计段结构改变的次数 transient int threshold; // 表示需要进行rehash的界限值 transient volatile HashEntry<K,V>[] table; final float loadFactor; // 表示负载因子}static final class HashEntry<K,V> { final K key; final int hash; volatile V value; final HashEntry<K,V> next;}
除了value不是final的,其它值都是final的,因此所有的节点的修改只能从头部开始
三.增删改查
remove
1.定位到segment
2.加锁
3.定位到要删除的数据
4.将要删除节点的前面所有节点整个复制一遍,最后一个节点指向要删除结点的下一个结点。
public V remove(Object key) {<span style="white-space:pre"></span>int hash = hash(key.hashCode());<span style="white-space:pre"></span>return segmentFor(hash).remove(key, hash, null);} V remove(Object key, int hash, Object value) { lock(); try { int c = count - 1; HashEntry<K,V>[] tab = table; int index = hash & (tab.length - 1); HashEntry<K,V> first = tab[index]; HashEntry<K,V> e = first; while (e != null && (e.hash != hash || !key.equals(e.key))) e = e.next; V oldValue = null; if (e != null) { V v = e.value; if (value == null || value.equals(v)) { oldValue = v; // All entries following removed node can stay // in list, but all preceding ones need to be // cloned. ++modCount; HashEntry<K,V> newFirst = e.next; for (HashEntry<K,V> p = first; p != e; p = p.next) newFirst = new HashEntry<K,V>(p.key, p.hash, newFirst, p.value); tab[index] = newFirst; count = c; // write-volatile } } return oldValue; } finally { unlock(); } }
put
1.通过hash算法得到对应的分段
2.向分段中push值
3.判断是否需要rehash
4.修改modcount
5.插入值,一律添加到Hash链的头部。
6.修改count
get
1.定位到segment
2.阅读count,保证happens_before(不是绝对安全)
3.获得值
4.如果为空则加锁重新读
size
1.先给3次机会,不lock所有的Segment,遍历所有Segment,累加各个Segment的大小得到整个Map的大小,
如果某相邻的两次计算获取的所有Segment的更新的次数(每个Segment都有一个modCount变量,
这个变量在Segment中的Entry被修改时会加一,通过这个值可以得到每个Segment的更新操作的次数)是一样的,
说明计算过程中没有更新操作,则直接返回这个值。
2.如果这三次不加锁的计算过程中Map的更新次数有变化,则之后的计算先对所有的Segment加锁,再遍历所有Segment计算Map大小,最后再解锁所有Segment
0 0
- ConcurrentHashMap
- ConcurrentHashMap
- ConcurrentHashMap
- ConcurrentHashMap
- ConcurrentHashMap
- ConcurrentHashMap
- ConcurrentHashMap
- ConcurrentHashMap
- ConcurrentHashMap
- ConcurrentHashMap
- ConcurrentHashMap
- ConcurrentHashMap
- ConcurrentHashMap
- ConcurrentHashMap
- ConcurrentHashMap
- concurrenthashmap
- ConcurrentHashMap
- ConcurrentHashMap
- 17、浅谈JSON
- Spark Master High Availability(HA)高可用配置的2种实现
- spark 作业调度
- 百度地图放大是报js错误
- Unable to locate Spring NamespaceHandler for XML schema namespace
- ConcurrentHashMap
- Spark Core Runtime分析: DAGScheduler, TaskScheduler, SchedulerBackend
- Spark的TaskScheduler和DagScheduler
- 初学makefile
- spring 动态定时器配置
- Spark 属性配置
- 根据官方api调用百度地图定位
- Sharding与数据库分区(Partition)的区别
- UE4教程推荐