目录
[4. CopyOnWriteArrayList](#4. CopyOnWriteArrayList)
[2. LinkedList(既是List,也是Queue)](#2. LinkedList(既是List,也是Queue))
4、ConcurrentLinkedQueue(高并发非阻塞)
5、LinkedBlockingQueue(最常用的阻塞队列)
6、ArrayBlockingQueue(固定容量的阻塞队列)
写在前面:
本文总结了Java集合(Collection)的各种常用实现类,这些是平时开发常用到的,在这里总结夯实基础,建议在阅读的时候自己亲自动手实践熟练下这些常用实现类。
一、List
1、ArrayList
底层结构:
基于动态数组(Object[])实现。
核心特点:
内存连续,支持快速的随机访问(通过索引 get/set 的时间复杂度为 O(1))。但在数组中间插入或删除元素时,需要移动后续所有元素,开销较大。
适用场景:
需要频繁通过下标读取数据的场景
注意事项:
默认初始容量为 10,扩容时会增加 50% 的容量并进行数组复制。如果提前知道数据量,建议在创建时指定初始容量,以减少扩容带来的性能损耗。
示例代码:
java
// 创建 ArrayList
ArrayList<String> list = new ArrayList<>();
// 添加元素
list.add("Apple");
list.add("Banana");
list.add("Cherry");
list.add("Date");
list.add("Elderberry");
System.out.println("初始列表: " + list);
// 在指定位置插入
list.add(1, "Avocado");
System.out.println("插入后: " + list);
// 获取元素
String first = list.get(0);
System.out.println("第一个元素: " + first);
// 修改元素
list.set(2, "Blueberry");
System.out.println("修改后: " + list);
// 检查元素是否存在
boolean contains = list.contains("Apple");
System.out.println("是否包含 Apple: " + contains);
// 获取大小
int size = list.size();
System.out.println("列表大小: " + size);
// 遍历 - for-each
System.out.print("for-each 遍历: ");
for (String item : list) {
System.out.print(item + " ");
}
System.out.println();
// 遍历 - Iterator
System.out.print("Iterator 遍历: ");
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
System.out.print(iterator.next() + " ");
}
System.out.println();
// 查找索引
int index = list.indexOf("Cherry");
System.out.println("Cherry 的索引: " + index);
// 删除元素
list.remove("Date");
System.out.println("删除 Date 后: " + list);
list.remove(0);
System.out.println("删除索引0后: " + list);
// 批量添加
ArrayList<String> anotherList = new ArrayList<>();
anotherList.add("Fig");
anotherList.add("Grape");
list.addAll(anotherList);
System.out.println("批量添加后: " + list);
// 批量删除
list.removeAll(anotherList);
System.out.println("批量删除后: " + list);
// 清空列表
list.clear();
System.out.println("清空后: " + list);
System.out.println("是否为空: " + list.isEmpty());
2、LinkedList
底层结构:
基于双向链表实现。
核心特点:
内存不连续,节点通过前驱和后继指针相连。在链表任意位置插入或删除元素时,只需修改指针指向(时间复杂度为 O(1)),无需移动元素。但随机访问需要从头或尾遍历,效率较低(时间复杂度为 O(n))。
适用场景:
频繁的首尾操作:虽然它适合中间增删,但在实际开发中,它更多被用来实现栈(Stack)或队列(Queue)。
复杂的增删业务:极少数需要在列表中间频繁进行大量插入、删除操作的特定算法场景。
注意事项:
如果要用到队列和栈,更推荐使用 ArrayDeque(基于数组的双端队列)。它的内存更紧凑,且在首尾操作的性能上通常优于 LinkedList。
示例代码:
java
// 创建 LinkedList
LinkedList<String> list = new LinkedList<>();
// 添加元素(尾部)
list.add("First");
list.add("Second");
list.add("Third");
list.add("Fourth");
System.out.println("初始列表: " + list);
// 添加到头部和尾部
list.addFirst("Head");
list.addLast("Tail");
System.out.println("添加头尾后: " + list);
// 使用 offer 方法(队列操作)
list.offer("Offer1");
list.offerFirst("OfferFirst");
list.offerLast("OfferLast");
System.out.println("offer 操作后: " + list);
// 获取元素(不删除)
String first = list.getFirst();
String last = list.getLast();
System.out.println("第一个元素: " + first);
System.out.println("最后一个元素: " + last);
// peek 方法(安全获取,空时返回 null)
String peek = list.peek();
String peekFirst = list.peekFirst();
String peekLast = list.peekLast();
System.out.println("peek: " + peek + ", peekFirst: " + peekFirst + ", peekLast: " + peekLast);
// 修改元素
list.set(2, "Modified");
System.out.println("修改后: " + list);
// 获取大小
System.out.println("列表大小: " + list.size());
// 遍历
System.out.print("for-each 遍历: ");
for (String item : list) {
System.out.print(item + " ");
}
System.out.println();
// 栈操作(pop/push)
String popped = list.pop();
System.out.println("弹出栈顶: " + popped);
System.out.println("弹出后: " + list);
list.push("Pushed");
System.out.println("压入后: " + list);
// 队列操作(poll/remove)
String polled = list.poll();
System.out.println("poll 取出: " + polled);
System.out.println("poll 后: " + list);
String removed = list.removeFirst();
System.out.println("removeFirst: " + removed);
System.out.println("removeFirst 后: " + list);
// 查找索引
int index = list.indexOf("Third");
System.out.println("Third 的索引: " + index);
// 删除元素
list.remove("Fourth");
System.out.println("删除 Fourth 后: " + list);
// 转换为数组
Object[] array = list.toArray();
System.out.print("数组内容: ");
for (Object obj : array) {
System.out.print(obj + " ");
}
System.out.println();
// 清空列表
list.clear();
System.out.println("清空后是否为空: " + list.isEmpty());
3、Vector、Stack
底层结构:
与 ArrayList 类似,基于动态数组。
核心特点:
Vector 的所有方法都加了 synchronized 关键字,是线程安全的,但因此带来了极大的性能开销。Stack 继承自 Vector,实现了标准的"后进先出"栈结构。
适用场景:
老旧系统维护:在现代高并发开发中,Vector 和 Stack 已经被淘汰,强烈不推荐在新项目中使用。
替代方案:
如果需要线程安全的 List,推荐使用 CopyOnWriteArrayList;如果需要栈结构,推荐使用 ArrayDeque。
4. CopyOnWriteArrayList
底层结构:
动态数组,采用"写时复制"(Copy-On-Write)机制。
核心特点:
读操作完全无锁,性能极高;写操作(增删改)时会加锁,并复制出一个全新的数组,在新数组上进行修改后再替换原数组。
适用场景:
读多写少需要线程安全场景:如系统中的配置列表等。这些场景下,绝大部分时间都在遍历读取,极少发生修改。
注意事项:
由于每次写操作都要复制整个数组,内存占用和 CPU 开销较大,绝对不能用于写操作频繁的场景。如果需要高频读写,不必须使用List情况下用ConcurrentHashMap或ConcurrentLinkedQueue性能更好。
示例代码:
java
// 创建 CopyOnWriteArrayList
CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
// 添加元素
list.add("Item1");
list.add("Item2");
list.add("Item3");
list.add("Item4");
System.out.println("初始列表: " + list);
// 在指定位置插入
list.add(1, "NewItem");
System.out.println("插入后: " + list);
// 如果不存在则添加
boolean added = list.addIfAbsent("Item5");
System.out.println("添加 Item5: " + added);
System.out.println("添加后: " + list);
// 批量添加(如果不存在)
String[] items = {"Item6", "Item7"};
int count = list.addAllAbsent(Arrays.asList( items));
System.out.println("批量添加了 " + count + " 个元素");
System.out.println("批量添加后: " + list);
// 获取元素
String first = list.get(0);
System.out.println("第一个元素: " + first);
// 修改元素
list.set(0, "Modified");
System.out.println("修改后: " + list);
// 获取大小
System.out.println("列表大小: " + list.size());
// 检查元素
boolean contains = list.contains("Item2");
System.out.println("是否包含 Item2: " + contains);
// 获取快照数组
Object[] snapshot = list.toArray();
System.out.print("快照数组: ");
for (Object obj : snapshot) {
System.out.print(obj + " ");
}
System.out.println();
// 遍历 - 迭代器(基于快照,线程安全)
System.out.print("Iterator 遍历: ");
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
System.out.print(iterator.next() + " ");
}
System.out.println();
// 遍历 - for-each
System.out.print("for-each 遍历: ");
for (String item : list) {
System.out.print(item + " ");
}
System.out.println();
// 查找索引
int index = list.indexOf("Item3");
System.out.println("\nItem3 的索引: " + index);
// 删除元素
list.remove("Item2");
System.out.println("删除 Item2 后: " + list);
list.remove(0);
System.out.println("删除索引0后: " + list);
// 批量删除
list.removeAll(List.of("Item6", "Item7"));
System.out.println("批量删除后: " + list);
// 保留指定元素
list.retainAll(List.of("Item3", "Item4", "Item5"));
System.out.println("保留后: " + list);
// 清空列表
list.clear();
System.out.println("清空后是否为空: " + list.isEmpty());
// 演示线程安全性:遍历时可以安全修改
System.out.println("\n=== 演示线程安全的遍历 ===");
CopyOnWriteArrayList<Integer> numbers = new CopyOnWriteArrayList<>();
numbers.add(1);
numbers.add(2);
numbers.add(3);
numbers.add(4);
numbers.add(5);
// 在遍历时添加元素不会抛出 ConcurrentModificationException
System.out.print("遍历时添加元素: ");
for (Integer num : numbers) {
System.out.print(num + " ");
if (num == 3) {
numbers.add(6); // 安全!不会影响当前迭代
}
}
System.out.println();
System.out.println("遍历完成后: " + numbers);
// 演示多线程场景
System.out.println("\n=== 演示多线程读写 ===");
CopyOnWriteArrayList<String> sharedList = new CopyOnWriteArrayList<>();
Thread writer1 = new Thread(() -> {
for (int i = 0; i < 5; i++) {
sharedList.add("Writer1-" + i);
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
Thread writer2 = new Thread(() -> {
for (int i = 0; i < 5; i++) {
sharedList.add("Writer2-" + i);
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
Thread reader = new Thread(() -> {
for (int i = 0; i < 3; i++) {
System.out.println("读取时刻: " + sharedList);
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
writer1.start();
writer2.start();
reader.start();
try {
writer1.join();
writer2.join();
reader.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("最终列表: " + sharedList);
System.out.println("列表大小: " + sharedList.size());
二、Set
1、HashSet
底层结构:
基于 HashMap 实现。当你把元素放入 HashSet 时,实际上是作为 HashMap 的 Key 存储的,而 Value 则是一个固定的静态 Object 对象。
核心特点:
去重原理:依赖 hashCode() 和 equals() 方法。如果两个对象的哈希值相同且 equals 为 true,则视为重复元素。
性能:添加、删除、查找的时间复杂度均为 O(1)。
允许空值:允许插入一个 null 元素。
适用场景:
绝大多数不需要顺序、只需要快速去重和查找的场景。
注意事项:
存入自定义对象时,必须重写 hashCode() 和 equals() 方法,否则无法正确去重。
示例代码:
java
// 1. 创建 HashSet
Set<String> set = new HashSet<>();
System.out.println("=== 创建 HashSet ===");
// 2. 添加元素 add()
System.out.println("\n=== 添加元素 ===");
set.add("Java");
set.add("Python");
set.add("C++");
set.add("JavaScript");
set.add("Go");
System.out.println("HashSet: " + set);
// 3. 获取大小 size()
System.out.println("\n=== 获取大小 ===");
System.out.println("元素个数: " + set.size());
// 4. 判断是否包含某元素 contains()
System.out.println("\n=== 判断是否包含 ===");
System.out.println("是否包含 'Java': " + set.contains("Java"));
System.out.println("是否包含 'Ruby': " + set.contains("Ruby"));
// 5. 删除元素 remove()
System.out.println("\n=== 删除元素 ===");
set.remove("C++");
System.out.println("删除 'C++' 后: " + set);
System.out.println("元素个数: " + set.size());
// 6. 判断是否为空 isEmpty()
System.out.println("\n=== 判断是否为空 ===");
System.out.println("是否为空: " + set.isEmpty());
// 7. 遍历 HashSet
System.out.println("\n=== 遍历 HashSet ===");
// 方式1: 增强 for 循环
System.out.println("方式1 - 增强 for 循环:");
for (String item : set) {
System.out.println(" " + item);
}
// 方式2: Iterator 迭代器
System.out.println("\n方式2 - Iterator 迭代器:");
Iterator<String> iterator = set.iterator();
while (iterator.hasNext()) {
System.out.println(" " + iterator.next());
}
// 方式3: forEach + Lambda
System.out.println("\n方式3 - forEach + Lambda:");
set.forEach(item -> System.out.println(" " + item));
// 8. 清空集合 clear()
System.out.println("\n=== 清空集合 ===");
set.clear();
System.out.println("清空后: " + set);
System.out.println("是否为空: " + set.isEmpty());
// 9. 批量操作
System.out.println("\n=== 批量操作 ===");
Set<String> set1 = new HashSet<>();
set1.add("A");
set1.add("B");
set1.add("C");
set1.add("D");
Set<String> set2 = new HashSet<>();
set2.add("C");
set2.add("D");
set2.add("E");
set2.add("F");
System.out.println("set1: " + set1);
System.out.println("set2: " + set2);
// addAll() - 并集
Set<String> union = new HashSet<>(set1);
union.addAll(set2);
System.out.println("并集 (addAll): " + union);
// retainAll() - 交集
Set<String> intersection = new HashSet<>(set1);
intersection.retainAll(set2);
System.out.println("交集 (retainAll): " + intersection);
// removeAll() - 差集
Set<String> difference = new HashSet<>(set1);
difference.removeAll(set2);
System.out.println("差集 (removeAll): " + difference);
// 10. 转换为数组 toArray()
System.out.println("\n=== 转换为数组 ===");
Set<String> set3 = new HashSet<>();
set3.add("X");
set3.add("Y");
set3.add("Z");
String[] array = set3.toArray(new String[0]);
System.out.print("数组: ");
for (String s : array) {
System.out.print(s + " ");
}
System.out.println();
// 11. HashSet 特性演示:不允许重复元素
System.out.println("\n=== HashSet 特性:不允许重复 ===");
Set<Integer> intSet = new HashSet<>();
intSet.add(1);
intSet.add(2);
intSet.add(3);
intSet.add(2); // 重复元素,不会添加成功
intSet.add(1); // 重复元素,不会添加成功
System.out.println("添加重复元素后: " + intSet);
System.out.println("元素个数: " + intSet.size());
// 12. HashSet 允许 null 值
System.out.println("\n=== HashSet 允许 null 值 ===");
Set<String> nullSet = new HashSet<>();
nullSet.add("A");
nullSet.add(null);
nullSet.add("B");
System.out.println("包含 null 的 HashSet: " + nullSet);
2、LinkedHashSet
底层结构:
基于 LinkedHashMap 实现。它在 HashMap 的基础上,增加了一条双向链表来维护元素的迭代顺序。
核心特点:
有序性:它保证了插入顺序。遍历时,元素的顺序与插入顺序一致。
性能:由于需要维护链表,性能略低于 HashSet。
适用场景:
需要去重,且希望遍历时保持元素插入顺序的场景。
示例代码(保持插入顺序的去重):
java
LinkedHashSet<String> linkedHashSet = new LinkedHashSet<>();
linkedHashSet.add("Java");
linkedHashSet.add("Python");
linkedHashSet.add("C++");
linkedHashSet.add("Java"); // 重复,不会添加
linkedHashSet.add("JavaScript");
linkedHashSet.add("Python"); // 重复,不会添加
System.out.println("结果: " + linkedHashSet);
//结果
结果: [Java, Python, C++, JavaScript]
3、TreeSet
底层结构:
基于 TreeMap 实现,底层数据结构是红黑树。
核心特点:
排序性:元素是自然排序(如数字从小到大,字母 A-Z)或者定制排序(通过 Comparator 接口)。
性能:由于是红黑树结构,添加、删除、查找的时间复杂度为 O(log n)。
不允许空值:插入 null 会抛出 NullPointerException(因为在排序比较时无法处理 null)。
适用场景:
需要对集合中的数据进行排序、范围查找(如查找大于 100 的所有元素)的场景。
示例代码:
java
//自定义排序(降序),new TreeSet<>()默认为升序
TreeSet<Integer> descendingSet = new TreeSet<>(Collections.reverseOrder());
descendingSet.add(45);
descendingSet.add(12);
descendingSet.add(78);
descendingSet.add(23);
descendingSet.add(56);
System.out.println("降序排列: " + descendingSet);
//结果
降序排列: [78, 56, 45, 23, 12]
//自定义对象排序
TreeSet<Student> students = new TreeSet<>(Comparator.comparingInt(Student::getScore).reversed());
students.add(new Student("张三", 85));
students.add(new Student("李四", 92));
students.add(new Student("王五", 78));
students.add(new Student("赵六", 95));
System.out.println("按分数降序排列:");
students.forEach(student ->
System.out.println(" " + student.getName() + ": " + student.getScore() + "分")
);
//结果
按分数降序排列:
赵六: 95分
李四: 92分
张三: 85分
王五: 78分
4、CopyOnWriteArraySet
底层结构:
内部维护了一个 CopyOnWriteArrayList。每次添加元素都遍历底层数组判断是否重复。
核心特点:
线程安全:它是线程安全的 Set。
写时复制:在执行添加(写)操作时,会复制一个新的数组,在新数组上修改,然后将原数组引用指向新数组。
读操作无锁:读取数据时不需要加锁,性能极高。
适用场景:读多写少的并发场景。
注意事项:
由于写操作涉及数组复制,开销很大,不适合频繁写入的场景;且它只能保证最终一致性,不适合强一致性要求的场景。
三、Queue
1、ArrayDeque
底层结构:
基于可动态扩容的循环数组实现。
核心特点:
它同时实现了 Queue 和 Deque(双端队列)接口。因为没有指针开销且利用了位运算,它的性能通常优于 LinkedList。JDK 官方也推荐使用它来替代过时的 Stack 类作为栈使用。
注意事项:
绝对不允许插入 null 元素,否则会抛出空指针异常。
示例代码(常用方法):
java
// ========== 1. 创建 ArrayDeque ==========
System.out.println("=== 创建 ArrayDeque ===");
ArrayDeque<String> deque = new ArrayDeque<>();
// ========== 2. 尾部添加元素(作为队列/栈使用)==========
System.out.println("\n=== 尾部添加元素 ===");
deque.addLast("A");
deque.addLast("B");
deque.addLast("C");
deque.offerLast("D");
deque.offerLast("E");
System.out.println("当前双端队列: " + deque);
// ========== 3. 头部添加元素 ==========
System.out.println("\n=== 头部添加元素 ===");
deque.addFirst("X");
deque.addFirst("Y");
deque.offerFirst("Z");
System.out.println("头部添加后: " + deque);
// ========== 4. 获取大小和判断为空 ==========
System.out.println("\n=== 基本信息 ===");
System.out.println("元素个数: " + deque.size());
System.out.println("是否为空: " + deque.isEmpty());
// ========== 5. 查看首尾元素(不删除)==========
System.out.println("\n=== 查看首尾元素(不删除)===");
System.out.println("第一个元素 (getFirst): " + deque.getFirst());
System.out.println("最后一个元素 (getLast): " + deque.getLast());
System.out.println("第一个元素 (peekFirst): " + deque.peekFirst());
System.out.println("最后一个元素 (peekLast): " + deque.peekLast());
System.out.println("查看后: " + deque);
// ========== 6. 从头部删除元素 ==========
System.out.println("\n=== 从头部删除元素 ===");
System.out.println("移除并返回第一个 (removeFirst): " + deque.removeFirst());
System.out.println("移除并返回第一个 (pollFirst): " + deque.pollFirst());
System.out.println("当前状态: " + deque);
// ========== 7. 从尾部删除元素 ==========
System.out.println("\n=== 从尾部删除元素 ===");
System.out.println("移除并返回最后一个 (removeLast): " + deque.removeLast());
System.out.println("移除并返回最后一个 (pollLast): " + deque.pollLast());
System.out.println("当前状态: " + deque);
// ========== 8. 遍历 ArrayDeque ==========
System.out.println("\n=== 遍历 ArrayDeque ===");
System.out.println("方式1 - 增强 for 循环:");
for (String item : deque) {
System.out.println(" " + item);
}
System.out.println("\n方式2 - forEach:");
deque.forEach(item -> System.out.println(" " + item));
System.out.println("\n方式3 - 迭代器(从头到尾):");
Iterator<String> iterator = deque.iterator();
while (iterator.hasNext()) {
System.out.println(" " + iterator.next());
}
System.out.println("\n方式4 - 降序迭代器(从尾到头):");
Iterator<String> descIterator = deque.descendingIterator();
while (descIterator.hasNext()) {
System.out.println(" " + descIterator.next());
}
2. LinkedList(既是List,也是Queue)
3、PriorityQueue(优先队列)
底层结构:
基于二叉堆(底层用数组存储)实现。
核心特点:
它不遵循先进先出原则。出队时,会根据元素的自然顺序(默认最小堆)或构造时传入的 Comparator 自定义规则,将优先级最高的元素先出队。
注意事项:
不允许插入 null,且不是线程安全的。如果在多线程环境下需要优先级队列,应使用 PriorityBlockingQueue。
示例代码(自定义排序):
java
// 使用 Lambda 表达式自定义排序(最大堆)
PriorityQueue<Integer> maxHeap = new PriorityQueue<>(
(a, b) -> b - a // 降序排列
);
maxHeap.offer(45);
maxHeap.offer(12);
maxHeap.offer(78);
maxHeap.offer(23);
maxHeap.offer(56);
System.out.print("出队顺序: ");
while (!maxHeap.isEmpty()) {
System.out.print(maxHeap.poll() + " ");
}
//结果
出队顺序: 78 56 45 23 12
//使用匿名内部类自定义排序:主要按成绩降序,次要按姓名字典序升序
PriorityQueue<Student> studentQueue = new PriorityQueue<>(new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
// 主要条件:按成绩降序(分数高的排前面)
int scoreCompare = Integer.compare(s2.getScore(), s1.getScore());
// 次要条件:如果成绩相同,按姓名字典序升序(字母/拼音靠前的排前面)
if (scoreCompare == 0) {
return s1.getName().compareTo(s2.getName());
}
return scoreCompare;
}
});
// 添加学生数据
studentQueue.offer(new Student("张三", 92));
studentQueue.offer(new Student("李四", 85));
studentQueue.offer(new Student("王五", 92));
studentQueue.offer(new Student("赵六", 78));
studentQueue.offer(new Student("钱七", 85));
studentQueue.offer(new Student("孙八", 95));
studentQueue.offer(new Student("周九", 78));
System.out.println("=== 学生排名(成绩降序,同分按姓名字典序)===");
int rank = 1;
while (!studentQueue.isEmpty()) {
Student student = studentQueue.poll();
System.out.println("第" + rank++ + "名: " + student.getName() +
" - " + student.getScore() + "分");
}
//结果
=== 学生排名(成绩降序,同分按姓名字典序)===
第1名: 孙八 - 95分
第2名: 张三 - 92分
第3名: 王五 - 92分
第4名: 李四 - 85分
第5名: 钱七 - 85分
第6名: 周九 - 78分
第7名: 赵六 - 78分
4、ConcurrentLinkedQueue(高并发非阻塞)
底层结构:
基于链表的无界队列。
核心特点:
采用 CAS(Compare-And-Swap)无锁算法保证线程安全。由于没有锁的阻塞和上下文切换开销,它在高并发场景下的吞吐量极高。 注意事项:它是非阻塞的,如果队列空了,调用 poll() 会直接返回 null,不会等待。
5、LinkedBlockingQueue(最常用的阻塞队列)
底层结构:
基于链表的可选有界队列。
核心特点:
它是阻塞队列(BlockingQueue 接口的实现)。当队列满时,插入操作会阻塞等待;当队列空时,获取操作会阻塞等待。它使用了两把锁(一把锁头部,一把锁尾部),实现了入队和出队的完全并行,因此在高并发下性能非常出色。
注意事项:
默认容量是 Integer.MAX_VALUE(近似无界)。如果在生产速度远大于消费速度时,极易导致 OOM(内存溢出),建议在创建时手动指定容量。它是 Java 线程池(ThreadPoolExecutor)默认使用的任务队列。
6、ArrayBlockingQueue(固定容量的阻塞队列)
底层结构:
基于数组的有界队列。
核心特点:
必须在创建时指定容量,且容量不可变。它内部只使用了一把锁来保证线程安全。
注意事项:
由于只有一把锁,入队和出队无法并行,在极高并发下性能略逊于 LinkedBlockingQueue。但它的内存占用是固定且可预测的,非常适合用于限流或需要严格控制资源占用的生产者-消费者模型。
7、DelayQueue(延迟队列)
底层结构:
内部基于 PriorityQueue 实现。
核心特点:
放入队列的元素必须实现 Delayed 接口(包含过期时间)。只有当元素的延迟时间到期后,才能通过 take() 或 poll() 方法将其取出。
注意事项:
非常适合处理订单超时自动取消、缓存过期清理等延迟任务场景。
到这里就结束了!