ArrayList
ArrayList底层是一个list接口的可变数组的非同步实现,包括null,扩容1.5倍,性能消耗严重,所以在初始化的时候,最好指定容量。
https://www.cnblogs.com/leesf456/p/5308358.html
LinkedList
-
LinkedList底层使用的双向链表结构
-
第一个节点数据prev = null ,最后一个数据节点next = null
https://www.cnblogs.com/leesf456/p/5308843.html
HashMap
- 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
-
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相同。