ConcurrentHashMap的理解

ConcurrentHashMap的put过程:
先贴源码:
final V putVal(K var1, V var2, boolean var3) {
if (var1 != null && var2 != null) {
int var4 = spread(var1.hashCode());
int var5 = 0;
ConcurrentHashMap.Node[] var6 = this.table;

        while(true) {
            int var8;
            while(var6 == null || (var8 = var6.length) == 0) {
                var6 = this.initTable();
            }

            ConcurrentHashMap.Node var7;
            int var9;
            if ((var7 = tabAt(var6, var9 = var8 - 1 & var4)) == null) {
                if (casTabAt(var6, var9, (ConcurrentHashMap.Node)null, new ConcurrentHashMap.Node(var4, var1, var2, (ConcurrentHashMap.Node)null))) {
                    break;
                }
            } else {
                int var10 = var7.hash;
                if (var7.hash == -1) {
                    var6 = this.helpTransfer(var6, var7);
                } else {
                    Object var11 = null;
                    synchronized(var7) {
                        if (tabAt(var6, var9) == var7) {
                            if (var10 < 0) {
                                if (var7 instanceof ConcurrentHashMap.TreeBin) {
                                    var5 = 2;
                                    ConcurrentHashMap.TreeNode var18;
                                    if ((var18 = ((ConcurrentHashMap.TreeBin)var7).putTreeVal(var4, var1, var2)) != null) {
                                        var11 = var18.val;
                                        if (!var3) {
                                            var18.val = var2;
                                        }
                                    }
                                }
                            } else {
                                var5 = 1;
                                ConcurrentHashMap.Node var13 = var7;

                                while(true) {
                                    if (var13.hash == var4) {
                                        Object var14 = var13.key;
                                        if (var13.key == var1 || var14 != null && var1.equals(var14)) {
                                            var11 = var13.val;
                                            if (!var3) {
                                                var13.val = var2;
                                            }
                                            break;
                                        }
                                    }

                                    ConcurrentHashMap.Node var15 = var13;
                                    if ((var13 = var13.next) == null) {
                                        var15.next = new ConcurrentHashMap.Node(var4, var1, var2, (ConcurrentHashMap.Node)null);
                                        break;
                                    }

                                    ++var5;
                                }
                            }
                        }
                    }

                    if (var5 != 0) {
                        if (var5 >= 8) {
                            this.treeifyBin(var6, var9);
                        }

                        if (var11 != null) {
                            return var11;
                        }
                        break;
                    }
                }
            }
        }

        this.addCount(1L, var5);
        return null;
    } else {
        throw new NullPointerException();
    }
}

1、判断Key、value是否为空
2、不为空则计算两次hash值,减少hash冲突
3、判断有没有进行初始化,如果没有初始化就调用initTable()方法来初始化
4、如果不存在hash冲突,则直接通过cas插入数据
5、判断是否在进行扩容,如果正在扩容则先进行扩容
6、如果有hash冲突,则通过synchronized加锁。
7、插入时有两种方式,一种以链表的方式插入(当该链表的数据小于阈值8时),一种是以红黑树的方式插入(当该链表的数据大于阈值8时)
8、如果添加成功就调用addCount()方法统计size,并且检查是否需要扩容

helpTransfer()方法源码:
final ConcurrentHashMap.Node<K, V>[] helpTransfer(ConcurrentHashMap.Node<K, V>[] var1, ConcurrentHashMap.Node<K, V> var2) {
if (var1 != null && var2 instanceof ConcurrentHashMap.ForwardingNode) {
ConcurrentHashMap.Node[] var3 = ((ConcurrentHashMap.ForwardingNode)var2).nextTable;
if (((ConcurrentHashMap.ForwardingNode)var2).nextTable != null) {
int var5 = resizeStamp(var1.length);

            while(var3 == this.nextTable && this.table == var1) {
                int var4 = this.sizeCtl;
                if (this.sizeCtl >= 0 || var4 >>> RESIZE_STAMP_SHIFT != var5 || var4 == var5 + 1 || var4 == var5 + MAX_RESIZERS || this.transferIndex <= 0) {
                    break;
                }

                if (U.compareAndSwapInt(this, SIZECTL, var4, var4 + 1)) {
                    this.transfer(var1, var3);
                    break;
                }
            }

            return var3;
        }
    }

    return this.table;
}

helpTransfer()不仅仅是等待正在扩容的线程进行扩容,而是加入到扩容的队伍一起进行扩容,相当于多个线程一起进行扩容。

get()源码:
public V get(Object var1) {
int var8 = spread(var1.hashCode());
ConcurrentHashMap.Node[] var2 = this.table;
ConcurrentHashMap.Node var3;
int var5;
if (this.table != null && (var5 = var2.length) > 0 && (var3 = tabAt(var2, var5 - 1 & var8)) != null) {
int var6 = var3.hash;
Object var7;
if (var3.hash == var8) {
var7 = var3.key;
if (var3.key == var1 || var7 != null && var1.equals(var7)) {
return var3.val;
}
} else if (var6 < 0) {
ConcurrentHashMap.Node var4;
return (var4 = var3.find(var8, var1)) != null ? var4.val : null;
}

        while((var3 = var3.next) != null) {
            if (var3.hash == var8) {
                var7 = var3.key;
                if (var3.key == var1 || var7 != null && var1.equals(var7)) {
                    return var3.val;
                }
            }
        }
    }

    return null;
}

流程:
计算hash值,定位到该table索引位置,如果是首节点符合就返回
如果遇到扩容的时候,会调用标志正在扩容节点ForwardingNode的find方法,查找该节点,匹配就返回
以上都不符合的话,就往下遍历节点,匹配就返回,否则最后就返回null

JDK1.7版本
结构:Segments数组+HashEntry数组+链表
线程同步方式:ReentrantLock+Segment+HashEntry,
JDK1.8版本
结构:Node数组+链表+红黑树
线程同步方式:synchronized+CAS+HashEntry+红黑树

参考:https://www.cnblogs.com/study-everyday/p/6430462.html
如有版权问题,请联系删除。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值