1 .首先先看看为什么要使用ConcurrentHashMap!
首先,ConcurrentHashMap是JDK5中引用的一个线程安全的支持高并发的HashMap集合类。它是弥补了HashMap和HashTable的不足而设计的;
1.HashMap是非线程安全的,在多线程操作环境下,使用Hashmap进行put操作可能会引起死循环,这是因为多线程会导致HashMap的Entry链表形成环形数据结构,一旦形成环形数据结构,Entry的next节点永远不为空,就会产生死循环获取Entry。导致CPU利用率接近100%,所以在并发情况下一般不使用HashMap。
2.HashTable效率较极低,如线程1使用put插入元素,而线程2,什么都做不了,必须等待线程1释放锁。
3. 故而ConcurrentHashMap 由一个 Segment 组成,Segment 代表”部分“或”一段“的,所以很多地方都会将其描述为分段锁。每次需要加锁的操作锁住的是一个 Segment,这样只要保证每个 Segment 是线程安全的,也就实现了全局的线程安全。
其使用了分段锁技术,
所谓分段锁技术就是数据分段,然后容器里就会有多把锁,每一把锁用于锁容器其中一部分数据, 那么当多线程访问容器里不同数据段的数据时,线程间就不会存在锁竞争,
从而可以有效的提高并发访问效率。
4.用 Volatile 关键字约束变量,从而协调读写线程间的内存可见性
由于内存可见性问题,未正确同步的情况下,写线程写入的值可能并不为后续的读线程可见。
根据 Java 内存模型,对 同一个 volatile 变量的写 / 读操作可以确保:写线程写入的值,能够被之后未加锁的读线程“看到”。
2.实现结构
看它的实现和继承:
public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
implements ConcurrentMap<K,V>, Serializable
同HashMap一样,也是继承了AbstractMap接口;实现了ConcurrentMap类和 Serializable类。
ConcurrentHashMap底层=数组+链表+红黑树。红黑树可以使hash散列更均匀。
如果还是采用单向列表方式,那么查询某个节点的时间复杂度为O(n);
jdk1.8中采用了红黑树的结构,那么查询的时间复杂度可以降低到O(logN),大大提高了检索效率。
先看java1.7中的结构:
到jdk1.8:
为了进一步提高并发性,在jdk1.8中则取消segment的概念,虽然源码保留了,但是只是为了考虑兼容性。采用table来保存数据,
transient volatile HashEntry<K,V> table
采用table数组元素作为锁,相对于jdk1.7,实现了对每一行数据进行加锁,进一步减少并发冲突的概率。
同时使用CAS + synchronized的方式来保证并发更新的安全。**CAS(Compare and Swap),即比较并替换,实现并发算法时常用到的一种技术。
几个重要属性:
private static final int MAXIMUM_CAPACITY = 1 << 30; node节点的最大容量
private static final int DEFAULT_CAPACITY = 16; 默认table初始化容量是16,且扩容必须是2的幂次方
static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; 数组最大值。
private static final int DEFAULT_CONCURRENCY_LEVEL = 16; 默认并发量,默认是16.
这个是segment数量,也就是说 ConcurrentHashMap 默认值有 16 个 Segments,所以理论上,这个时候,最多可以同时支持 16 个线程并发写,只要它们的操作分别分布在不同的 Segment 上。这个值可以在初始化的时候设置为其他值,但是一旦初始化以后,它是不可以扩容的。
private static final float LOAD_FACTOR = 0.75f;
static final int TREEIFY_THRESHOLD = 8; 链表 转红黑树的阈值界限
static final int UNTREEIFY_THRESHOLD = 6;
static final int MIN_TREEIFY_CAPACITY = 64;
transient volatile Node<K,V>[] table; 装载Node节点的table.默认为null,采用懒加载的方式,直到第一次插入数据的时候才会进行初始化操作,数组的大小总是为2的幂次方。
privat