[小笔记] Java 集合类

线程不安全集合类

HashMap

HashMap 的默认容量大小为 16,重载因子为 0.75

计算 keyhash 值然后做 mod 运算,将其存放在 bucket 中(默认容量为 16),如果出现冲突,bucket 上的数据就变成链表。如果单个链表上的数据量达到 8,构建红黑树来储存数据(一种自平衡二叉查询树)。当数据容量达到容量 * 重载因子后 (默认是 16 * 0.75 = 12)或者多次出现数据碰撞,扩容容量,将原来的容量 * 2,然后重新构建 bucket 中的数据。

bucket 中未出现数据碰撞时,数据查询复杂度 O(1)

bucket 中出现数据碰撞时,但是链表节点数量小于 8,数据查询复杂度 O(n)

bucket 中的数据出现碰撞,且节点数量大于等于 8,数据查询复杂度为 O(logn)

HashSet

其内部也是通过 HashMap 实现,只是将其 Value 用一个固定的值 PRESENT

LinkedHashMap

继承于 HashMap,默认的 HashMap 中的元素是无序的,LinkedHashMap 内部自定义了 LinkedHashMap#Entry,它继承于 HashMap#Entry,不同的是它也是一个双向链表的节点。这样就 LinkedHashMap 中的元素就变得有序,可以通过 putFirst()putLast() 方法来分别控制在链表的头部或者尾部来添加数据。

LinkedHashSet

它就相当于 HashSet 之于 HashMap,它继承于 HashSet,内部也通过 LinkedHashMap 来使其元素有序。

ArrayList

内部通过数组来保存元素,当数组的容量不足以来容纳元素时,会将其数组扩容,扩容会将原来旧的容量 * 2,如果之前的数组容量为 0,那么新的数组容量是 10。参考以下代码:

Java 复制代码
private Object[] grow(int minCapacity) {
    int oldCapacity = elementData.length;
    if (oldCapacity > 0 || elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { // 扩容
        int newCapacity = ArraysSupport.newLength(oldCapacity,
                minCapacity - oldCapacity, /* minimum growth */
                oldCapacity >> 1           /* preferred growth */);
        // 复制旧数组的数据        
        return elementData = Arrays.copyOf(elementData, newCapacity);
    } else {
        // 之前的容量为 0,默认初始化大小为 10 的数组
        return elementData = new Object[Math.max(DEFAULT_CAPACITY, minCapacity)];
    }
}

private Object[] grow() {
    return grow(size + 1);
}

LinkedList

内部使用双向链表来储存元素,移除/添加 首部/尾部 的元素性能比 ArrayList 高,但是随机读写的性能比 ArrayList 低。它实现了栈/队列的方法。栈:pop() / push();队列:poll / offer()

ArrayDeque

内部使用数组来储存元素,默认的数组大小为 17。其中通过 head / tail 来记录首部和尾部的 index。它同样实现了栈/队列中的方法,相对于 LinkedList,它的特点是内部实现是数组。

PriorityQueue

使用数组来储存元素,默认数组大小为 11,使用堆排序来确认优先级。

线程安全集合类

ConcurrentHashMap

Java 7: 写操作分段加锁(分为 16 个段),读取操作无需加锁。 Java 8: 写操作锁单个 bucket / entry,初始化 table 时线程安全通过 CAS 保证线程安全,读操作无需加锁。

Hashtable

读写都会锁 Hashtable 对象,相对于 ConcurrentHashMap 性能较差。

CopyOnWriteArrayList

写的时候加锁,构建新的数组,将原来的数组复制到新的数组,然后将新的数据添加到新的数据末尾,源码:

Java 复制代码
public boolean add(E e) {
    synchronized (lock) {
        Object[] es = getArray();
        int len = es.length;
        es = Arrays.copyOf(es, len + 1);
        es[len] = e;
        setArray(es);
        return true;
    }
}

读取不需要加锁。

CopyOnWriteArraySet

内部通过 CopyOnWriteArrayList 实现,插入的时候会先检查是否存在元素,不存在才插入,它也具备 CopyOnWriteArrayList 的特性。

PriorityBlockingQueue

相对于 PriorityQueue,其读写都会通过 ReentrantLock 加锁。

LinkedBlockingDeque

读写都通过 ReentrantLock 加锁,内部通过双向链表储存数据,它也实现了堆和队列的接口。

相关推荐
静若繁花_jingjing11 小时前
IDEA下载
java·ide·intellij-idea
代码丰12 小时前
函数式接口+default接口+springAi 中的ducumentReader去理解为什么存在default接口的形式
java
果汁华13 小时前
java学习连续打卡30天(1)
java
武子康13 小时前
Java-171 Neo4j 备份与恢复 + 预热与执行计划实战
java·开发语言·数据库·性能优化·系统架构·nosql·neo4j
m0_6398171514 小时前
基于springboot火锅店管理系统【带源码和文档】
java·spring boot·后端
会编程的林俊杰15 小时前
SpringBoot项目启动时的依赖处理
java·spring boot·后端
一叶飘零_sweeeet15 小时前
深度拆解汽车制造系统设计:用 Java + 设计模式打造高扩展性品牌 - 车型动态生成架构
java·设计模式·工厂设计模式
王家羽翼-王羽15 小时前
nacos 3.1.0 运行主类报错 com.alibaba.cloud.nacos.logging.NacosLoggingAppRunListener
java
影子240116 小时前
oralce创建种子表,使用存储过程生成最大值sql,考虑并发,不考虑并发的脚本,plsql调试存储过程,java调用存储过程示例代码
java·数据库·sql