写在前边的一些话:在jdk1.5之前,HashTable为了保证线程安全,在每个方法上都加上了synchronized关键字,在并发场景下效率是特别低的。在1.5之后使用ConcurrentHashMap对它进行了替代,使用分段锁的技术,在使用时只需要将元素所在的段锁住,因此段与段之间是可以高并发的。在jdk8之后使用CAS+synchronized的组合方式来实现并发场景下的线程安全。
1、初始化
public ConcurrentHashMap(int initialCapacity) {
if (initialCapacity < 0)
throw new IllegalArgumentException();
int cap = ((initialCapacity >= (MAXIMUM_CAPACITY >>> 1)) ?
MAXIMUM_CAPACITY :
tableSizeFor(initialCapacity + (initialCapacity >>> 1) + 1));
this.sizeCtl = cap;
}
在ConcurrentHashMap中提供了一个空的构造函数用来创建一个新的并且默认大小是16的空Map。当指定初始化容量时,计算了sizeCtl=(1.5*initialCapacity +1),然后向上取最近的2的n次方。
sizeCtl为负值表示的table正在被初始化(-1)或者扩容(-(1+当前正在扩容线程的数量)),table为null时,该值默认为0。通常在扩容之后,将sizeCtl设置为下次需要扩容的阈值(0.75*n)。
2、put过程分析
- 这里我们应该注意到的是:与HashMap不同的是,在链表的长度达到8时有可能不会进行红黑树转换而仅仅做的是数组的扩容
final V putVal(K key, V value, boolean onlyIfAbsent) {
//这里判断key和value都不能为空,如果为空就抛出异常
if (key == null ||