Java存储数据List Map Set 简单对比

ArrayList

ArrayList底层是一个list接口的可变数组的非同步实现,包括null,扩容1.5倍,性能消耗严重,所以在初始化的时候,最好指定容量。

https://www.cnblogs.com/leesf456/p/5308358.html

LinkedList

linkedList 数据存储结构

  • LinkedList底层使用的双向链表结构

  • 第一个节点数据prev = null ,最后一个数据节点next = null

https://www.cnblogs.com/leesf456/p/5308843.html

HashMap

haskMap数据结构

  • HashMap 底层使用Node[]数组实现,数组中每一项是个单向链表,即数组和链表的结合体;当链表长度大于一定阈值时(超过了8个),链表转换为红黑树,这样减少链表查询时间。
  • HashMap是基于哈希表的Map接口的非同步实现,允许使用null值和null键,但不保证映射的顺序。
  • 默认构造函数 构建一个初始容量为16,负载因子为0.75的HashMap。
  • 会根据key的hash算法来决定其在数组中的存储位置,在根据equals方法决定其在该数组位置上的链表中的存储位置。
  • 当需要取出一个Node时,也会根据key的hash算法找到其在数组中的存储位置,再根据equals方法从该位置上的链表中取出该Node。

https://blog.csdn.net/weixin_43167418/article/details/103775842
https://www.jianshu.com/p/7bfada54689c

Hashtable

  • Hashtable是基于哈希表的Map接口的同步实现,不允许使用null值和null键,Hashtable中的映射不是有序的
  • 底层使用Entry[]数组实现,数组中每一项是个单链表,即数组和链表的结合体
  • 会根据key的hash算法来决定其在数组中的存储位置,在根据equals方法决定其在该数组位置上的链表中的存储位置
  • 取出一个Entry时,也会根据key的hash算法找到其在数组中的存储位置,再根据equals方法从该位置上的链表中取出该Entry。
  • synchronized是针对整张Hash表的,即每次锁住整张表让线程独占,这意味着它是线程安全的
  • 默认加载因子是 0.75

https://blog.csdn.net/qq_27574367/article/details/88527853

ConcurrentHashMap

  • 不接受null key null value
  • JDK1.7的锁分段技术可有效提升并发访问率
    HashTable容器在竞争激烈的并发环境下表现出效率低下的原因是所有访问HashTable的线程都必须竞争同一把锁,假如容器里有多把锁,每一把锁用于锁容器其中一部分数据,那么当多线程访问容器里不同数据段的数据时,线程间就不会存在锁竞争,从而可以有效提高并发访问效率,这就是ConcurrentHashMap所使用的锁分段技术。首先将数据分成一段一段地存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据的时候,其他段的数据也能被其他线程访问。
  • JDK1.8 中

    数据结构:

    数组+链表+红黑树

    并发原理:

    cas乐观锁+synchronized锁

    加锁对象:

    数组每个位置的头节点

    Put方法:

    先根据key的hash值定位桶位置,然后cas操作获取该位置头节点,接着使用synchronized锁锁住头节点,遍历该位置的链表或者红黑树进行插入操作。
    并发问题:如果put过程中其他线程正在扩容怎么办?
    答:暂停put,进行扩容,然后在进行put操作.

    Get方法:

    根据key的hash值定位,遍历链表或者红黑树,获取节点。
    并发问题:假如此时正好有别的线程正在对数组扩容怎么办?
    答:没关系,扩容的时候不会破坏原来的table,遍历任然可以继续,不需要加锁。

https://www.cnblogs.com/ylspace/p/12726672.html

HashSet

  • HashSet由哈希表(实际上是一个HashMap实例)支持。
  • 不保证set的迭代顺序,并允许使用null元素。
  • 基于HashMap实现,API也是对HashMap的行为进行了封装,可参考HashMap
  • 默认加载因子0.75
  • Value是一个固定值,实际存储的是key
// 定义一个虚拟的Object对象作为HashMap的value,将此对象定义为static final。  
private static final Object PRESENT = new Object();  

https://www.iteye.com/blog/zhangshixi-673143

LinkedHashMap

linkHashMap数据存储结构

  • LinkedHashMap是Map接口的哈希表和链接列表实现,具有可预知的迭代顺序。此实现提供所有可选的映射操作,并允许使用null值和null键。此类不保证映射的顺序,特别是它不保证该顺序恒久不变

  • 维护着一个运行于所有条目的双重链接列表。此链接列表定义了迭代顺序,该迭代顺序可以是插入顺序或者是访问顺序.

链表元素数据结构:

/** 
 * 双向链表的表头元素。 
 */  
private transient Entry<K,V> header; 

/** 
 * LinkedHashMap的Entry元素。 
 * 继承HashMap的Entry元素,又保存了其上一个元素before和下一个元素after的引用。 
 */  
private static class Entry<K,V> extends HashMap.Entry<K,V> {  
    Entry<K,V> before, after;  
    ……  
} 

  • 排序模式:LinkedHashMap定义了排序模式accessOrder,该属性为boolean型变量,对于访问顺序,为true;对于插入顺序,则为false。

  • 判断当排序模式accessOrder为true时,记录访问顺序,将最新访问的元素添加到双向链表的表头,并从原来的位置删除。

  • 该哈希映射的迭代顺序就是最后访问其条目的顺序,这种映射很适合构建LRU缓存。LinkedHashMap提供了removeEldestEntry(Map.Entry<K,V> eldest)方法,在将新条目插入到映射后,put和 putAll将调用此方法。该方法可以提供在每次添加新条目时移除最旧条目的实现程序,默认返回false,这样,此映射的行为将类似于正常映射,即永远不能移除最旧的元素。

protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {  
    return false; // 永远不移除就旧元素 
} 

此方法通常不以任何方式修改映射,相反允许映射在其返回值的指引下进行自我修改。

如果用此映射构建LRU缓存,则非常方便,它允许映射通过删除旧条目来减少内存损耗。

例如:

private static final int MAX_ENTRIES = 10;  
protected boolean removeEldestEntry(Map.Entry eldest) {  
    return size() > MAX_ENTRIES;  
}  

测试结果仅有十个数据
自动排除掉了A元素B元素

https://www.cnblogs.com/wang-meng/p/7583491.html

https://www.iteye.com/blog/zhangshixi-673789

LinkedHashSet

  • 对于LinkedHashSet而言,它继承与HashSet、又基于LinkedHashMap来实现的。LinkedHashSet底层使用LinkedHashMap来保存所有元素,它继承与HashSet,其所有的方法操作上又与HashSet相同。

https://www.iteye.com/blog/zhangshixi-673319

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值