java 集合底层_java集合底层实现总结

1List :元素可以重复,可以存null

1.1 ArrayList:采用数组,非线程安全,默认初始量10,扩容机制1.5倍,Fail-Fast机制,快速失败机制。查找快速,增删需要一个个复制移动元素,适合查找。Jdk8中默认初始量为0。

1.2 Vector:和ArrayList差不多,是线程安全的。

1.3 LinkedList:带头尾指针的双向链表,实现了Queue接口,Deque(Queue的子接口),可当做栈、队列使用。增删快速,查找需要链表一个个找,适合增删操作。

2 Set:元素不重复

2.1 HashSet:基于HashMap实现的,HashSet底层使用HashMap来保存所有元素。元素保存在map的key中。

2.2 LinkedHashSet:它继承与HashSet、又基于LinkedHashMap来实现的,迭代顺序可为插入顺序或是访问顺序

2.3 TreeSet: 其底层使用的就是TreeMap,用红黑树来存储数据,不能存null,不然抛异常,实现了SortedSet接口,可以用Comparealbe自然排序,或者自定义Comparetor接口

3.1HashMap:key value键值对,可以存null值,key是final的不可修改。 数组+链表 HashMap内部维护着一个散列数组(就是一个存放元素的数组),每个列表都是一个桶,我们称其为散列桶,而当我们向HashMap中存入一组键值对时,HashMap首先获取key这个对象的hashcode()方法的返回值,得出一个数字,再对桶总数取余,这个数字就是这组键值对要存入散列数组中的下标位置。桶为空就加进去,不为空就用equals()查看散列数组的链表里是否已经包含这个对象,HashMap会将每组键值对封装为一个Entry的实例,然后将该实例存入链表,否则就替换value。

那么在获取元素时,HashMap同样先根据key的hashcode值进行散列算法,找到它在散列数组中的位置,然后遍历该位置的链表,找到该key所对应的value之后返回。HashMap 的实例有两个参数影响其性能:初始容量16 和加载因子(默认0.75). 达到16*0.75=12时,map扩容一倍成32.

(定位桶位置没有用取余,而是用&,容量都是2的幂次方,因为&(length-1),这样结果是1或者0,分布更均匀)

fail-fast机制:通过volatile类型的modCount域,modCount顾名思义就是修改次数,对HashMap内容的修改都将增加这个值,那么在迭代器初始化过程中会将这个值赋给迭代器的expectedModCount。

Jdk8中的hashmap:大致过程差不多,只是链表中采用链表+红黑树,当超过8时转换成红黑树,低于6转回链表,在扩容中和jdk7不同的是,采用&高位,利用结果1还是0判断是原位置还是原位置+扩容量的位置。Jdk7采用重新计算hash值。

在JDK7 存在死循环和数据丢失问题。

数据丢失:

并发赋值被覆盖: 在 createEntry 方法中,新添加的元素直接放在头部,使元素之后可以被更快访问,但如果两个线程同时执行到此处,会导致其中一个线程的赋值被覆盖。

已遍历区间新增元素丢失: 当某个线程在 transfer 方法迁移时,其他线程新增的元素可能落在已遍历过的哈希槽上。遍历完成后,table 数组引用指向了 newTable,新增元素丢失。

新表被覆盖: 如果 resize 完成,执行了 table = newTable,则后续元素就可以在新表上进行插入。但如果多线程同时 resize ,每个线程都会 new 一个数组,这是线程内的局部对象,线程之间不可见。迁移完成后resize 的线程会赋值给 table 线程共享变量,可能会覆盖其他线程的操作,在新表中插入的对象都会被丢弃。

死循环:

HashMap在put的时候,插入的元素超过了容量(由负载因子决定)的范围就会触发扩容操作,就是rehash,这个会重新将原数组的内容重新hash到新的扩容数组中,链表尾部的数据会成为新链表的头部,在多线程的环境下,存在同时其他的元素也在进行put操作,如果hash值相同,可能出现同时在同一数组下用链表表示,造成闭环,导致在get时会出现死循环,所以HashMap是线程不安全的。

JDK8 在 resize 方法中完成扩容,并改用尾插法,不会产生死循环,但并发下仍可能丢失数据。可用 ConcurrentHashMap 或 Collections.synchronizedMap 包装成同步集合。

Hashmap不安全:https://www.jianshu.com/p/e2f75c8cce01

3.2TreeMap:底层使用红黑树,key不能为null,不然抛异常。实现了SortedMap接口,可以用Comparealbe自然排序,或者自定义Comparetor接口

3.3 LinkedHashMap:具有可预知的迭代顺序,该迭代顺序可以是插入顺序或者是访问顺序。

3.3 HashTable:线程安全的。不可以存null值。

3.4 CurrentHashMap:jdk7中,采用数组+链表,Segment分段枷锁,Segment是继承Reentranlock,从而实现线程安全。Entry的value和next Entry都是valitaile的,保证可见性。Key是final。

Jdk8中,参考了1.8HashMap的实现方式,采用了数组,链表,红黑树的实现方式,采用Node节点,利用synchronized+CAS加锁实现的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值