Java 集合篇(Collection、HashMap、ConcurrentHashMap)

Java集合主要从三个方面来说明:

1. Java集合基本概念和对比

    1. 集合的继承关系图

                                         

   2. 集合继承关系说明

      Java集合主要分类对比:

           单例集合:Collection, 单列集合,主要存储一个值

                 List: List 集合元素有序,可以重复

                      ArrayList:底层是数组,查询快,增删慢,线程不安全, 每次扩容是1.5 倍扩容

                      LinkedList: 底层是链表, 增删快,查询慢, 线程不安全

                      Vector: 底层是数组,查询快,增删慢, 线程安全,安全主要是底层是每个方法有synchronized修饰, 0.75 扩容

                 Set: set集合元素无序,但是不可重复

                      HashSet: 底层主要有hash算法实现,通过hashcode() 和equals()  方法实现元素不可重复

                      LinkedHashSet: 有序的set

                      TreeSet: 底层由二叉树实现的有序Set

           键值对集合:Map, 是双列结合,主要表现为键值对存在

                     HashMap:最常用的Map实现类,其中元素无序,线程不安全,允许一个Key 为null,多个value为null

                     TreeMap:与HashMap 最大的区别就是有序,他是按照某种特定的规则有序,底层是红黑树实现有序的,但是线程也是不安全的,

2. HashMap

    1. HashMap的底层数据结构

           JDK1.7 : 数据  +  链表

                            

           JDK1.8 : 数据  +  链表  +  红黑树(在jdk1.8 之后,当链表长度大于8 时,就裂变为红黑树,目的是提高性能)

                               

   2.  HsahMap 的主要特点和其他Map的对比

            HashMap 是一个无序的键值对双列集合,在HashMap中允许一个Key 为Null, 多个value 为null, 线程不安全。如果在Put 键值对的时候有key 已存在,就会覆盖原来key 的value. 从HashMap的主要特点就可以进行选择Map集合, 如果元素无序,为了更高的性能不需要考虑线程安全时就选择HashMap, 如果需要有序的Map集合就用TreeMap,来重写排序原则或者使用原来的自然排序,如果需要线程安全的就使用 ConcurrentHashMap.

   3. HashMap 的原理

           HashMap 底层原理: HashMap 底层主要是有数组和链表组成,数组是HashMap的主体结构,链表主要是为了解决Hash冲突存在的。当定位到的数组没有链表结构,则对于查询、新增都很快,如果定位的数组有链表,新增的时间复杂度为O(n),每次新增首先判读key 是否存在,如果存在就覆盖新值,不存在就新增。查询的时候需要遍历整个链表,通过key 对象的eauals方法的逐一对比。所以性能考虑,HashMap的链表出现越少,性能越好。

         HashMap 主要通过Entry 来存key-value储键值对,每一个Key_value 键值对组成一个Entry 实体,Entry类实际上是一个单向的链表结构,它具有next 指针,指向下一个Entry 实体,依次来解决hash冲突的问题,因为HashMap是按照Key的hash值来计算Entry在HashMap中存储的位置的,如果hash值相同,而key内容不相等,那么就用链表来解决这种hash冲突。

   4. HashMap 扩容

        初始size为16,扩容:newsize = oldsize*2,size一定为2的n次幂

        扩容针对整个Map,每次扩容时,原来数组中的元素依次重新计算存放位置,并重新插入插入元素后才判断该不该扩容,有可能无效扩容(插入后如果扩容,如果没有再次插入,就会产生无效扩容)当Map中元素总数超过Entry数组的75%,触发扩容操作,为了减少链表长度,元素分配更均匀

    5. HashMap 源码

         自己去品尝,每个人品尝的味道都不一样,总之一句话,酸爽。

3. ConcurrentHashMap

    1. 底层原理实现

        1. JDK 1.7(数组 + 链表, 由分段锁实现线程安全问题)

                jdk1.7 是由Segment 数组、HashEntry 组成,HashEntry和 HashMap 一样,仍然是数组 + 链表。Segment是一种 可重入锁ReentrantLock,在ConcurrentHashMap里扮演锁的角色,HashEntry则用于存储键值对数据。一个ConcurrentHashMap里包含一个Segment数组,Segment的结构和HashMap类似,是一种数组和链表结构, 一个Segment里包含一个HashEntry数组,每个HashEntry是一个链表结构的元素, 每个Segment守护一个HashEntry数组里的元素,当对HashEntry数组的数据进行修改时,必须首先获得它对应的Segment锁。

       2. JDK 1.8(数组+链表+红黑树, 用CAS无锁算法 + synchronized来实现线程安全)

             

       JDK 1.8 :  结构和HashMap的结构一样,其中抛弃了分段锁,采用了CAS+synchronized来保证并发安全,1.7 中存放数据的 HashEntry 改为 Node,但作用都是相同的。其中val和next用了volatile 修饰,保证了在内存中的可见性。

       2.  常用方法  

         put方法:

        根据key计算出hashcode,在定位到Node,如果当前Node为空表示可以写入数据,利用 CAS 尝试写入,失败则自旋保证成功。

       判断是否需要扩容;

      如果都不满足,使用synchronized锁写入数据;

      判断是否需要转换成红黑树。

     get方法:

     根据计算出来的hashcode寻址,如果就在桶上就直接返回值;

     如果是红黑树就按照红黑树的方式获取值;

    如果不满足就按照链表的方式遍历获取值。

哪里写的不对,哪里需要补充请大家多多指教,谢谢!
 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值