• JavaEE 多线程下的HashTable、HashMap、ConcurrentHashMap


    HashMap

    特点

    (1)HashMap是线程不安全的,意味着多线程下不能使用该方法,可能会导致意想不到的结果。如果我们细细的查看源码,就会发现HashMap方法没有synchronized这样的加锁操作。

    (2)初始化容量:HashMap的默认容量是16.把1像左移动4个字节,变成了10000,是2的4次方也就是16。put后才开辟空间。

    (3)默认加载因子:0.75f。

    (4)底层实现:数组、链表、红黑树。

            Java中的哈希表采用链地址法,当桶中的存储元素(链表)大于8的时候,进行一次判断。当数组的长度大于64的时候,自动转换成红黑树。转化成红黑树的两个必要条件:桶节点的数量大于8、整个数组的长度大于64。

    (5)如何扩容:每一次扩容大小是当前容量的2倍。当map键值对数大于等于加载因子*数组长度时,可能发生扩容;或者当某个桶的链表长度大于8,但是数组长度小于64的时候。

    (6)允许键值对中键的值为null。

    Hashtable

    特点

    (1)Hashtable的方法中,均只是简单加了synchronized关键字,在多线程下,是线程安全的。

    (2)初始化容量:初始化容量为11。

    (3)底层实现:数组和链表。

    (4)如何扩容:newsize = olesize * 2+1。拷贝过程中需要该线程完成整个扩容过程,涉及大量的元素拷贝,效率比较低。

    (5)Hashtable方法,直接使用了一把大锁,如果多个线程访问同一个Hashtable就很容易产生冲突。

    (6)不允许键值对中键的值为null。

    ConcurrentHashMap

    特点

    (1)ConcurrentHashMap方法中,针对性加锁,线程安全。

            对于读的操作,没有加锁,而是使用了volatile关键字保证了内存可见性。只对于写的操作加锁,加锁使用synchronized关键字。细化了锁的粒度。锁的时候不是直接锁住整个对象,而是每一个哈希桶,降低了锁的冲突概率。

    (2)ConcurrentHashMap更加充分的使用CAS特性,避免了出现重量级锁的情况。

    (3)针对扩容的方式进行优化,采用化零为整的策略。使用锁分段技术,把若干个哈希桶分成一个 "段" ,对每个段分别加锁。降低锁竞争的概率。

    (4)不允许键值对中键的值为null。

    三者区别

    (1)HashMap线程不安全,其他的线程安全。

    (2)Hashtable使用一把大锁,导致锁冲突概率很高,ConcurrentHashMap的每一个哈希桶使用一把锁,锁冲突的概率小。

    (3)ConcurrentHashMap相对于Hashtable使用了其他优化策略,比如使用CAS特性、使用锁分段技术等。

    (4)HashMap中,key值允许为null,另外两个不允许。

  • 相关阅读:
    VScode 使用ESlint检查代码
    【Unity实战100例】Unity内部软键盘输入制作
    【计算机网络】——数据链路层(应用:局域网、广域网、设备 )
    【CPP_Primer_Plus】C++ IDE推荐
    【leetcode】【剑指offer Ⅱ】028. 展平多级双向链表
    力扣每日一题 神奇字符串
    Ubuntu上安装Chrome浏览器
    openMVS
    【操作系统笔记十五】操作系统面试问题总结
    Qt 样式设置
  • 原文地址:https://blog.csdn.net/Naion/article/details/126228595