美文网首页Java 杂谈
Java并发包之ConcurrentHashMap

Java并发包之ConcurrentHashMap

作者: LandHu | 来源:发表于2018-12-07 12:04 被阅读55次

之前整理了一份Java中常用的集合类的基本特性:
Java常用集合类图解
详细介绍了HashMap:
HashMap之浅析
HashMap之Hash碰撞
HashMap之扩容机制
HashMap之线程安全

本文分析并补充一下线程安全的HashMap-ConcurrentHashMap
参考优秀博文: 深入并发包 ConcurrentHashMap

补充:
  1. CocurrentHashMap能完全代替Hashtable吗?
    我们知道Hashtable是synchronized的,会锁定整个map,当Hashtable的大小增加到一定的时候,性能会急剧下降,因为迭代时需要被锁定很长的时间。ConcurrentHashMap同步性能更好,因为它仅仅根据同步级别对map的一部分进行上锁。
    HashTable虽然性能上不如ConcurrentHashMap,但并不能完全被取代,两者的迭代器的一致性不同的,HashTable的迭代器是强一致性的,而ConcurrentHashMap是弱一致的。 ConcurrentHashMap的get,clear,iterator 都是弱一致性的。 Doug Lea 也将这个判断留给用户自己决定是否使用ConcurrentHashMap。
    那么什么是强一致性和弱一致性呢?
    get方法是弱一致的,是什么含义?可能你期望往ConcurrentHashMap底层数据结构中加入一个元素后,立马能对get可见,但ConcurrentHashMap并不能如你所愿。换句话说,put操作将一个元素加入到底层数据结构后,get可能在某段时间内还看不到这个元素,若不考虑内存模型,单从代码逻辑上来看,却是应该可以看得到的。

  2. ConcurrentHashMap.computeIfAbsent 在 JDK 1.8 存在 BUG

public class ConcurrentHashMapDemo{

    private Map<Integer,Integer> cache =new ConcurrentHashMap<>(15);

    public static void main(String[]args){
        ConcurrentHashMapDemo ch =    new ConcurrentHashMapDemo();
        System.out.println(ch.fibonaacci(80));        
    }

    public int fibonaacci(Integer i){        
        if(i==0||i ==1) {                
            return i;        
    }

    return cache.computeIfAbsent(i,(key) -> {
        System.out.println("fibonaacci : "+key);
        return fibonaacci(key -1)+fibonaacci(key - 2);        
    });       

    }
}

如果你将这个代码跑起来,你会发现的这个程序将进入死循环,而无法结束。通过阅读源码发现,ConcurrentHashMap.computeIfAbsent() 方法停留在了一个 ReservationNode 对象上,感兴趣的朋友可阅读java.util.concurrent.ConcurrentHashMap#transfer扩容源码

解决方法:

  • 升级到JDK 1.9,已经修复该Bug
  • 不要用递归的方式创建 ConcurrentHashMap 对象

参考:HashMap?面试?我是谁?我在哪


技术讨论 & 疑问建议 & 个人博客

版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 3.0 许可协议,转载请注明出处!

相关文章

网友评论

    本文标题:Java并发包之ConcurrentHashMap

    本文链接:https://www.haomeiwen.com/subject/zcsocqtx.html