sizeCtl:表初始化和调整大小控制字段.如果为负数,则表正在初始化或调整大小,此时写操作将自旋
Node的Hash节点数据节点类型:MOVED=-1,列表的格式正在转换;TREEBIN=-2,树节点的Hash;RESERVED=-3,临时Hash;HASH_BITS=0x7fffffff,正常节点Hash
final V putVal(K key, V value, boolean onlyIfAbsent) { if (key == null || value == null) throw new NullPointerException(); //将key转换为hash码,尽可能的保证hash的均匀分布,且hash值必须大于0,因为小于0的是特殊hash int hash = spread(key.hashCode()); int binCount = 0; for (Node[] tab = table;;) { Nodef; int n, i, fh; //如果tab为空 if (tab == null || (n = tab.length) == 0) //则创建table tab = initTable(); //查询tab中第1个元素,如果为空,则将第一个元素直接插入 else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) { if (casTabAt(tab, i, null, new Node(hash, key, value, null))) break; // no lock when adding to empty bin } //hash获取,在JDK1.8中,ConcurrentHashMap中所有列表的第一个node作为锁 //内置了不同的hash码,来标记不同的状态, //将节点的元素数据移植到新表上面 else if ((fh = f.hash) == MOVED) tab = helpTransfer(tab, f); else { V oldVal = null; //对节点f加锁 synchronized (f) { //二次验证节点f if (tabAt(tab, i) == f) { //如果f节点的Hash值正常,也就是大于0 if (fh >= 0) { binCount = 1; for (Nodee = f;; ++binCount) { K ek; //如果存在hash一致的 if (e.hash == hash && ((ek = e.key) == key || (ek != null && key.equals(ek)))) { oldVal = e.val; //且允许覆盖,则覆盖 if (!onlyIfAbsent) e.val = value; break; } Nodepred = e; //否则链表尾插入 if ((e = e.next) == null) { pred.next = new Node(hash, key, value, null); break; } } } //如果节点f为树类型节点 else if (f instanceof TreeBin) { Nodep; binCount = 2; if ((p = ((TreeBin)f).putTreeVal(hash, key, value)) != null) { oldVal = p.val; if (!onlyIfAbsent) p.val = value; } } } } //如果链表节点个数大于8且table数据个数大于默认上限64,则转化为红黑树 //如果小于64,则只是尝试扩容 if (binCount != 0) { if (binCount >= TREEIFY_THRESHOLD) treeifyBin(tab, i); if (oldVal != null) return oldVal; break; } } } addCount(1L, binCount); return null; } • ConcurrentHashMap#putVal • initTable()源码 private final Node[] initTable() { Node[] tab; int sc; while ((tab = table) == null || tab.length == 0) { //获取系统的sizeCtl赋值给sc,如果sizeCtl小于0,则认为此时的数据已经被其余线程修改,自身进入等待...... if ((sc = sizeCtl) < 0) Thread.yield(); // 当前线程自旋 //CAS操作 //获取当前对象的SIZECTL与sc比较,如果系统的SIZECTL等于sc,则将SIZECTL修改为-1 else if (U.compareAndSwapInt(this, SIZECTL, sc, -1)) { try { if ((tab = table) == null || tab.length == 0) { //为Table设置元素存取上限 int n = (sc > 0) ? sc : DEFAULT_CAPACITY; @SuppressWarnings("unchecked") Node[] nt = (Node[])new Node[n]; table = tab = nt; sc = n - (n >>> 2); } } finally { sizeCtl = sc; } break; } } return tab; }
ConcurrentHashMap | HashMap | Hashtable | |
数据安全? | 安全 | 不安全 | 安全 |
性能? | 快 | 快 | 慢 |
Copyright © 2023 leiyu.cn. All Rights Reserved. 磊宇云计算 版权所有 许可证编号:B1-20233142/B2-20230630 山东磊宇云计算有限公司 鲁ICP备2020045424号
磊宇云计算致力于以最 “绿色节能” 的方式,让每一位上云的客户成为全球绿色节能和降低碳排放的贡献者