• Hash


    HashMap

    HashMap是一个采用哈希表的键值对集合,这里从如下几个问题解读HashMap。

    1. HashMap工作原理?

    2. 如何做到fail-fast?可靠吗?

    3. 容量超过负载因子定义的容量,怎么处理?

    4. capacity & load factor 设置参考因素?

    5. HashMap为何线程不安全?

    6. 为什么容量必须为2的整数次幂?

    HashMap工作原理

    HashMap 是一个采用哈希表实现的键值对集合。put元素时,通过hash计算出下标,然后存储在合适位置的bucket中。get元素时,通过hash计算出下标,然后遍历桶中的链表获取元素。存储基于一个数组,然后数组的每一个元素都是链表。

    如何做到fail-fast?可靠吗?

    HashMap内部有一个modCount属性,累计每一次结构变更操作。当生成迭代器时,会记录当前的modCount值,此后每次迭代都会拿记录的值与当前值比较,有差异,则抛出ConcurrentModificationException。但是,这个属性没有volatile标记,也没有同步语义等。并发操作下不存在happens-before关系,故不一定可靠。

    容量超过负载因子定义的容量,怎么处理?

    会触发resize,对所有的元素做rehash,重新分布元素,并按照当前总容量的2倍扩容。扩容后,阈值等也会随之调整。

    capacity & load factor设置参考因素?

    hashmap基于hashing的原理,本质上是用空间换时间来提升搜索效率,这2个参数的设置参考因素也是基于这一点来进行。

    1.capacity代表容量,过小容易导致过多的resize动作;过高容易浪费大量的存储空间以及提高检索时间。

    2.load factor表示负载比例,比例过低,容量浪费大量的空间;比例过高,产生碰撞的几率更大,更多的碰撞会降低搜索的效率。

    HashMap为何线程不安全?

    1. 并发做节点增删时,一个线程新增的节点,挂在另一个线程的删除节点之后,可能导致数据丢失;
    2. 并发做resize时,可能导致节点死循环;

    为什么容量必须为2的整数次幂?

    hash值找到对应索引的方法如下:

    /**

     * Returns index for hash code h.

     */

    static int indexFor(int h, int length) {

        // assert Integer.bitCount(length) == 1 : "length must be a non-zero power of 2";

        return h & (length-1);

    }

     

    首先,length为2的整数次幂的话,h&(length-1)就相当于对length取模,这样便保证了散列的均匀,同时也提升了效率;

    其次,length为2的整数次幂的话,为偶数,这样length-1为奇数,奇数的最后一位是1,这样便保证了h&(length-1)的最后一位可能为0,也可能为1(这取决于h的值),即与后的结果可能为偶数,也可能为奇数,这样便可以保证散列的均匀性,而如果length为奇数的话,很明显length-1为偶数,它的最后一位是0,这样h&(length-1)的最后一位肯定为0,即只能为偶数,这样任何hash值都只会被散列到数组的偶数下标位置上,这便浪费了近一半的空间。

    因此,length取2的整数次幂,是为了使不同hash值发生碰撞的概率较小,这样就能使元素在哈希表中均匀地散列。

    • HashTable

    1. 为何线程安全?
    2. 获取index相对HashMap如何?

    为何线程安全?

    HasTable相对HashMap,基本上对所有的公开方法都增加了synchronized关键字,相对HashMap多了线程安全特性。

    获取index相对HashMap如何?

    相比HashMap的获取index逻辑,性能要差一些。HashMap只是一个取模动作,HashTable是取模后再取余。

    • ConcurrentHashMap

    ConcurrentHashMap默认并发级别是16,通过Segment来分块管理entry集合。每个Segment都持有一个重入锁,限制并发编辑操作。

    相比HashTable并发时锁整个Map,ConcurrentHashMap是锁Segment,锁粒度变小,整体性能提升。

    同时对迭代器友好,在并发迭代时,不会抛出ConcurrentModificationException异常。

    • TreeMap

    基于红黑树实现。深入解读可参考:http://blog.csdn.net/chenssy/article/details/26668941

    • LinkedHashMap

    LinkedHashMap继承HashMap,在HashMap的功能上叠加了有序性(插入顺序,访问顺序),元素链表支持双向等功能。

    LinkedHashMap扩展了HashMap中的Entry,在其中增加了Entry<K, V> before, after属性。通过这2个属性,支持双向链表。同时独立于table数组外有一个Entry<K, V> header节点,通过这个来遍历整个双向链表。

    有序性则通过accessOrder属性来控制。

    • 一致性哈希

     将桶数量设置为一个极大值,机器与数据视为节点都可以被映射到这一个近似无穷大的空间中。每个机器节点可以管理顺序条件下的一组空间,数据节点hash后落在这组空间内的,会交由机器节点管理。当机器增删时,会产生管理空间的分割与合并处理,顺带归属这些空间的数据节点会做迁移。这样可以做到有限规模的数据迁移。在增删节点时,因为hash计算的缘故,机器节点分摊的数据节点可能不平衡。为了尽量做到平衡性,引入虚拟节点。每一个真实机器节点会映射几个虚拟节点。出于维护平衡性,虚拟节点会尽量分摊数据节点,做到尽量均匀。

    详细可参考:

    http://blog.csdn.net/cywosp/article/details/23397179

  • 相关阅读:
    IDEA Inspections详解
    IDEA 阿里编码规范插件
    IDEA Save Actions插件
    IDEA Lombok插件
    设计模式-简单工厂模式与工厂模式
    DAO设计模式
    Jcrop+strut2+jsp实现图片剪切
    Spring的Bean的作用域
    Spring的事务机制
    windows 下 Redis 主从 读写分离
  • 原文地址:https://www.cnblogs.com/asfeixue/p/7718195.html
Copyright © 2020-2023  润新知