无药可救的我本来打算直接上ConcurrentHashMap...结果发现自己都写不明白...所以结合一下HashMap一起写了
<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">------------划重点------------</span>
1.1初始化一个HashMap的过程:
loadFactor(装载因子)=0.75,initialCapacity(初始容量)=16,
threshold = loadFactor * capacity(当数组中的使用大小>=threshold 时,entry 数组容量扩充为当前大小的两倍,扩充时对当前entry对象数组的中的元素全部rehash,并填充数组,并重新设置threshold值)。
创建Entry对象数组的大小为如下代码片段
int capacity = 1;
while(capacity < initialCapacity)
capacity <<= 1
capacity 才是真正的Entry对象数组大小,默认情况下为16
HashMap初始化的是entry对象数组
2.1初始化一个ConcurrentHashMap的过程:
和HashMap一样有 initialCapacity和loadFactor属性,不过还多了一个concurrencyLevel;调用空构造函数的值分别为16,0.75,16
基于上述三个属性值计算的的size值:
int sshift = 0;
int sszie = 1;
while(ssize < concurrencyLevel){
++sshift;
ssize <<= 1 ;// ssize = ssize * 2
}
在concurrencyLevel为16的情况下最终计算出的ssize = 16
然后将ssize传入Segment的newArray方法,创建大小为16的Segment对象数组,创建segment对象时,就是创建一个指定大小为
------------------------------
1.2对于key为null的情况,HashMap的做法为获取Entry数组的第一个Entry对象,并基于第一个entry对象的next属性遍历,如果找到key为null的entry对象,则将value更新;如果没有找到的话,取当前数组的第一个entry对象:e,创建一个新的entry对象e2,key为null ,然后e2 的next 是e
2.2concurrentHashMap不论是key ,还是value 为null 都会抛出NullPointerException
------------------------------
1.3HashMap的put:
先获取key对象本身的hashCode值,然后对此hashCode做hash操作,实现如下
h ^= k.hashCode();
h ^= (h >>> 20) ^ (h >>> 12);
return h ^ (h >>> 7) ^ (h >>> 4);
得到的值与(capacity -1)进行按位与操作,得到对应的数组位置,然后通过next进行遍历,寻找hash值一样的的entry对象,有则更新,无则添加
2.3ConcurrentHashMap的put:
和hashMap同样的hash操作后得到的值获取对应数组的segment对象,方法如下:
return segments[(hash >>> segmentShift)&segmentMask]
找到segment对象后,进行lock操作,接着判断当前存储的对象个数加1后是否大于threshold,如果大于,当前HashEntry对象数组大小扩大两倍,并将之前存储的对象都全部rehash,接下来的操作和HashMap一样,所以此处省略n个字。
完成设值之后释放锁,整个put动作完成。
总结:ConcurrentHashMap基于concurrencyLevel划分出多个segment,从而避免每次put操作都得锁住整个数组。在默认情况下,最佳情况下可以允许16个线程并发无阻塞的操作集合对象。
---------------------------
其它的方法都差不多的。。。不想写了。。。下次再写吧