Java集合005 --- ConcurrentHashMap
作者:互联网
前言
ConcurrentHashMap内部实现和HashMap类似,都采用了数组+单链表+红黑树的结构;区别是:ConcurrentHashMap是线程安全的;
ConcurrentHashMap线程安全在JDK1.7中由ReentLock和分段锁保证,在JDK1.8版本做了优化,使用synchronized+CAS+分段锁保证
为啥1.8要是用synchronized呢? 在印象中,synchronized不是效率很低么?synchronized其实也是可重入的,并且在近几个版本做了优化
这里不过多的写ConcurrentHashMap原理,这里只是说明下ConcurrentHashMap中使用的自旋锁和分段锁思想
直接上ConcurrentHashMap的put方法:
final V putVal(K key, V value, boolean onlyIfAbsent) { if (key == null || value == null) throw new NullPointerException(); // 计算hash, 和HashMap类似 int hash = spread(key.hashCode()); int binCount = 0; // 循环, 注意这里没有结束条件, 是依靠其中的流程退出循环; 这是为了在CAS时, 使用自旋锁思想 for (Node<K,V>[] tab = table;;) { Node<K,V> f; int n, i, fh; // 数组为空, 初始化数组 if (tab == null || (n = tab.length) == 0) tab = initTable(); // 未命中, CAS添加元素; 添加失败, 重新开启循环 // 这里添加失败的原因可能是并发场景下,其他线程修改了取值 else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) { if (casTabAt(tab, i, null, new Node<K,V>(hash, key, value, null))) break; // no lock when adding to empty bin } else if ((fh = f.hash) == MOVED) tab = helpTransfer(tab, f); else { // 命中后需要加锁, 将元素merge到树或者链表,或者数组 V oldVal = null; // 注意这里的锁对象f是指定索引数组元素, 这就是分段锁 synchronized (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)))) { oldVal = e.val; if (!onlyIfAbsent) e.val = value; break; } Node<K,V> pred = e; if ((e = e.next) == null) { pred.next = new Node<K,V>(hash, key, value, null); break; } } } else if (f instanceof TreeBin) { Node<K,V> p; binCount = 2; if ((p = ((TreeBin<K,V>)f).putTreeVal(hash, key, value)) != null) { oldVal = p.val; if (!onlyIfAbsent) p.val = value; } } } } if (binCount != 0) { if (binCount >= TREEIFY_THRESHOLD) treeifyBin(tab, i); if (oldVal != null) return oldVal; break; } } } addCount(1L, binCount); return null; }
这块就写这么多吧,写不下去了。。。。。
标签:key,Node,ConcurrentHashMap,hash,005,binCount,tab,Java,null 来源: https://www.cnblogs.com/sniffs/p/12969291.html