zoukankan      html  css  js  c++  java
  • java集合Map体系

    一、常用Map类

    HashMap:最常用的实现类。java8以前:数组+链表;java8:数组+链表/红黑树

    LinkedHashMap:相比较HashMap,元素顺序排列。

    TreeMap:key自动排序

    HashTable:效率不高的线程安全类。

    ConccurentHashMap:效率高的线程安全类。

    二、HashMap的底层实现

    HashMap是存储映射关系的集合,key-value方式。基本元素时entry,每个entry就是一个键值对映射。

    HashMap内部维护的key的是Set集合,保证key的唯一,所以HashMap的Key必须要保证重写过HashCode和Equals方法。维护value的是Collection集合。

        transient Set<K>        keySet;
        transient Collection<V> values;

    put方法的逻辑:

    1、如何HashMap没有初始化,则初始化,定义size。

    2、对key求Hash值,然后在根据size计算下标位置。

    3、如果没有碰撞,即下标位置没有元素,直接添加元素。

    4、如果碰撞了,以链表的方式放到链表后面。

    5、如果链表长度超过阀值(8),就把链表转成红黑树。

    6、如果链表长度低于6,就把红黑树转回链表。

    7、如果该下标存在相同的key,就替换掉value。

    8、如果元素的数量达到总容量0.75,就需要resize(扩容2倍重排)。

    java8之后,HashMap使用数组+链表+红黑树的方式。

    1、为什么要添加红黑树

    当散列算法出现极端情况时,即所以的hash值计算出来的的下标都一样,那么链表中的数据会很庞大,不利于查询。所以当同一下标位置的元素超过一定数量,就将链表转换成红黑树,提高查询效率。

    2、为什么使用key的Hash值及HashMap如何由hash找到元素。

    维护key的是set集合,以为着key的唯一。而确定唯一的方式就是重写后的equals方法,但是如果要只使用equals方法比较,在数据元素较多时,效率会慢。所以通过保证equals方法相同的key,hash也相同,来确定同样的key会计算出同样的下标。这样就可以提高比较的效率。同时,因为不保证不同的key的hash一定不同,所以会有碰撞产生。

    那么HashMap如何通过key的hash值计算出小标呢。

    看代码:

        static final int hash(Object key) {
            int h;
            return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
        }

    这段代码的意义在于尽量保证散列值的均匀,将32位int值右移16位,在与原hash值异或运算。

     Node<K,V>[] tab; Node<K,V> p; int n, i;
            if ((tab = table) == null || (n = tab.length) == 0)
                n = (tab = resize()).length;
            if ((p = tab[i = (n - 1) & hash]) == null)
                tab[i] = newNode(hash, key, value, null);

    只看部分代码:i = (n - 1) & hash

    这段代码中,i 就是需要的下标位置,n是map的容量大小。将上一步结果的hash值与n做与运算得出下标。

    3、将HashMap包装成一个线程安全的map

            Map<String,String> map = new HashMap();
            Map safeHashMap = Collections.synchronizedMap(map);

    这样包装,和HashTable没什么区别,都是把整个map加锁。

    二、HashTable效率为什么低

    因为他把整个map加了锁,同一时间只能操作一个元素。

    三、同样是线程安全,为什么ConccurentHashMap效率高

    java5有了ConccurentHashmap,通过锁细粒度化,将整个锁拆解成多个锁进行优化。通过分段锁Segment实现。例如:一个map有12个元素,没三个元素一把锁,这样理论上就有HashMap的4倍效率。早期的ConccurentHashMap默认分了16段锁,就有HashMap16倍效率。

    java8之后ConccurentHashMap使用:CAS+synchronized使锁跟家细化。它在找到下标之后,如果没有元素,则使用CAS循环插入,失败则进入下一次循环。如果下标有元素节点,就获取该下标点的synchronized锁,进入同步操作。这样就使得每一个元素都相当于一个锁,使锁更加的细粒化,并且对于空下标,可以直接插入,同时用CAS保证该操作线程安全。

    就算这个世道烂成一堆粪坑,那也不是你吃屎的理由
  • 相关阅读:
    分段路由的复兴
    动态维护FDB表项实现VXLAN通信
    neutron dhcp 高可用
    wpf
    从0到1设计一台8bit计算机
    哇塞的Docker——vscode远程连接Docker容器进行项目开发(三)
    中通消息平台 Kafka 顺序消费线程模型的实践与优化
    飞机大战 python小项目
    看透确定性,抛弃确定性
    如何根据普通ip地址获取当前地理位置
  • 原文地址:https://www.cnblogs.com/whalesea/p/12940410.html
Copyright © 2011-2022 走看看