ConcurrentHashMap两个版本比较

Map<String,String> map = new ConcurrentHashMap<String,String>()

1.7版本

初始容量默认为16段(Segment),使用分段锁设计

不对整个Map加锁,而是为每个Segment加锁

当多个对象存入同一个Segment时,才需要互斥

最理想的状态为16个对象分别存入16个Segment,并行数量16

使用方式与HashMap无异

只有16把锁,后续扩容之后也只有16把锁,一个锁锁多个链表数组(与1.8比较)

1.8版本

CAS(ComparableAndSwap)交换算法和同步锁

CAS(ComparableAndSwap)交换算法
V:要更新的值
E:预期的值
N:新值
当V == E时,V == N

如果在修改过程中,V已经发生变化,V != E ,则取消当前赋值操作,做下一次赋值操作
多线程访问,一个线程在修改过程中,时间片没了,下一个线程也去修改完成,上一个线程分到时间片发现V已经发生变化

同步锁锁的是表头对象,拿到锁的对象要先做节点遍历。查看有没有相同的key,
相同覆盖,不同,则挂在最后一个节点的next上

每个链表的第一个都是表头,都有锁,创建新的也是会有(和1.7不同之处)

public V put(K key, V value) {
return putVal(key, value, false);//用putVal()来判断传入的值
}

final V putVal(K key, V value, boolean onlyIfAbsent) {
       if (key == null || value == null) throw new NullPointerException();
       int hash = spread(key.hashCode());
      int binCount = 0;
         for (Node<K,V>[] tab = table;;) {
         Node<K,V> f; int n, i, fh;//f为Node中的第一个数组中的对象,作为锁头的对象

         if (tab == null || (n = tab.length) == 0)
                 tab = initTable();
         else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {//用Cab方法去判断如果插入的为null表明里面没有值,
                 if (casTabAt(tab, i, null,                                        插入成功,为第一个,上锁,成为锁头
                 new Node<K,V>(hash, key, value, null)))
                 break; // no lock when adding to empty bin
}

synchronized (f) {//对f上锁,插入到这个链表数组中的元素都要经过锁头f获得锁,遍历对比
if (tabAt(tab, i) == f) {        如有相同键的对象,覆盖,没有,插入到最后一个
if (fh >= 0) {
binCount = 1;
for (Node<K,V> e = f;; ++binCount) {
K ek;
if (e.hash == hash &&
((ek = e.key) == key ||
(ek != null && key.equals(ek)))) {//如果key相等
oldVal = e.val;
if (!onlyIfAbsent)
e.val = value;//值覆盖
break;
}
Node<K,V> pred = e;//找到最后一个
if ((e = e.next) == null) {//如果它的下一个是null
pred.next = new Node<K,V>(hash, key,//将自己的地址存到它的next中
value, null);
break;
}
}
}

发布了32 篇原创文章 · 获赞 85 · 访问量 3031

猜你喜欢

转载自blog.csdn.net/S9264L/article/details/104861408