JDK1.7ConcurrentHashMap源码解读
使用传统HashTable保证线程问题,是采用synchronized锁将整个HashTable中的数组锁住,
在多个线程中只允许一个线程访问Put或者Get,效率非常低,但是能够保证线程安全问题。
Jdk官方不推荐在多线程的情况下使用HashTable或者HashMap,建议使用ConcurrentHashMap分段HashMap。
效率非常高。
ConcurrentHashMap将一个大的HashMap集合拆分成n多个不同的小的HashTable(Segment),默认的情况下是分成16个不同的
Segment。每个Segment中都有自己独立的HashEntry<K,V>[] table;
核心参数:
initialCapacity —16 初始化
loadFactor HashEntry<K,V>[] table; 加载因子0.75
concurrencyLevel 并发级别 默认是16
cas与乐观锁机制原理(简单)
一直卡死,消耗cpu资源,一直重试。
hashtable缺点
底层使用synchronized锁实现的,但是将整个数组都给锁住了。
1.7ConcurrentHashMap
将一个大的ConcurrentHashMap集合拆分成n多个不同的hashtable,在每个小的hashtable中都有自己的table【】
package com.gtf.xc;
import java.util.HashMap;
public class MyConcurrentHashMap
<K, V> {
/**
* segments
*/
private HashMap<K,V>[] segments;
public MyConcurrentHashMap() {
segments=new HashMap[16];
//注意是懒加载
}
public void put(K key, V value) {
//第一次计算key,计算key存放在哪一个hashtable
int segmentsIndex =key.hashCode()& (segments.length - 1);
HashMap<K, V> segment = segments[segmentsIndex];
//segment == null
if (segment == null) {
segment=new HashMap<>();
}
segment.put(key,value);
segments[segmentsIndex]=segment;
}
public V get(K key) {
int segmentsIndex =key.hashCode()& (segments.length - 1);
HashMap<K, V> segment = segments[segmentsIndex];
if (segment != null) {
return segment.get(key);
}
return null;
}
public static void main(String[] args) {
MyConcurrentHashMap<Object, Object> objectObjectMyConcurrentHashMap = new MyConcurrentHashMap<>();
for (int i = 0; i < 10; i++){
objectObjectMyConcurrentHashMap.put(i,i);
}
for (int i = 0; i < 10; i++) {
objectObjectMyConcurrentHashMap.get(i);
System.out.println( objectObjectMyConcurrentHashMap.get(i));
}
}
}
没有获取到锁的线程
- 自旋 缓存当前对应冲突链表
- 每次检查 当前缓存链表头节点是否发生变化
- 如果发生变化的情况下 缓存最新
- 自旋的次数最多为64
实现原理
- 由多个不同的sement对象组成
- 使用 luck锁+cas
- unsafe 直接查询主内存最新的数据
- 使用cas做修改
JDK1.8ConcurrentHashMap
ConcurrentHashMap1.8的取出取消segment分段设计,采用对CAS + synchronized保证并发线程安全问题,将锁的粒度拆分到每个index
下标位置,实现的效率与ConcurrentHashMap1.7相同。