并发容器详解
一、知识概述
Java并发包(java.util.concurrent)提供了一系列线程安全的集合类,这些并发容器在多线程环境下提供了更好的性能和安全性。相比使用synchronized包装的同步集合(如Collections.synchronizedList),并发容器采用了更精细的锁策略,实现了更高的并发性能。
并发容器概览
┌─────────────────────────────────────────────────────────────────────┐
│ Java并发容器体系 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ List实现 │ │
│ │ CopyOnWriteArrayList 写时复制列表 │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ Set实现 │ │
│ │ CopyOnWriteArraySet 写时复制集合 │ │
│ │ ConcurrentSkipListSet 跳表有序集合 │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ Map实现 │ │
│ │ ConcurrentHashMap 分段锁/并发哈希表 │ │
│ │ ConcurrentSkipListMap 跳表有序映射 │ │
│ │ ConcurrentLinkedQueue 无界并发队列 │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ 阻塞队列实现 │ │
│ │ ArrayBlockingQueue 有界数组阻塞队列 │ │
│ │ LinkedBlockingQueue 可选有界链表阻塞队列 │ │
│ │ PriorityBlockingQueue 无界优先级阻塞队列 │ │
│ │ DelayQueue 延迟队列 │ │
│ │ SynchronousQueue 同步队列(零容量) │ │
│ │ LinkedTransferQueue 传输队列 │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────┘
同步集合 vs 并发容器
| 特性 | 同步集合 | 并发容器 |
|---|---|---|
| 锁粒度 | 全表锁 | 细粒度锁/无锁 |
| 并发性能 | 低(串行访问) | 高(并行访问) |
| 迭代安全 | 需要同步 | 弱一致性迭代 |
| 空指针 | 可能抛出 | 不抛出 |
| 推荐使用 | 不推荐 | 推荐 |
二、知识点详细讲解
2.1 ConcurrentHashMap
2.1.1 基本使用
java
import java.util.*;
import java.util.concurrent.*;
/**
* ConcurrentHashMap基本使用
*/
public class ConcurrentHashMapDemo {
public static void main(String[] args) {
System.out.println("=== ConcurrentHashMap基本使用 ===\n");
basicOperations();
atomicOperations();
bulkOperations();
}
/**
* 基本操作
*/
private static void basicOperations() {
System.out.println("【基本操作】\n");
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
// 添加元素
map.put("one", 1);
map.put("two", 2);
map.put("three", 3);
System.out.println("初始map: " + map);
// 获取元素
System.out.println("get('two'): " + map.get("two"));
System.out.println("getOrDefault('four', 4): " + map.getOrDefault("four", 4));
// 删除元素
map.remove("one");
System.out.println("remove后: " + map);
// 替换
map.replace("two", 20);
System.out.println("replace后: " + map);
// 条件替换
boolean replaced = map.replace("two", 20, 200);
System.out.println("条件替换结果: " + replaced + ", map: " + map);
// 大小
System.out.println("size: " + map.size());
System.out.println("isEmpty: " + map.isEmpty());
// 遍历
System.out.println("\n遍历:");
map.forEach((k, v) -> System.out.println(" " + k + " = " + v));
System.out.println();
}
/**
* 原子操作
*/
private static void atomicOperations() {
System.out.println("【原子操作】\n");
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
// putIfAbsent - 不存在才添加
map.put("count", 0);
map.putIfAbsent("count", 100); // 不会覆盖
System.out.println("putIfAbsent后: " + map);
// computeIfAbsent - 不存在则计算添加
map.computeIfAbsent("new", k -> k.length());
System.out.println("computeIfAbsent后: " + map);
// computeIfPresent - 存在则更新
map.computeIfPresent("count", (k, v) -> v + 1);
System.out.println("computeIfPresent后: " + map);
// compute - 重新计算
map.compute("count", (k, v) -> v == null ? 0 : v + 10);
System.out.println("compute后: " + map);
// merge - 合并
map.merge("count", 5, (oldVal, newVal) -> oldVal + newVal);
System.out.println("merge后: " + map);
// replaceAll - 批量替换
map.put("a", 1);
map.put("b", 2);
map.replaceAll((k, v) -> v * 10);
System.out.println("replaceAll后: " + map);
System.out.println();
System.out.println("原子操作方法:");
System.out.println(" putIfAbsent(K, V) 不存在才添加");
System.out.println(" computeIfAbsent(K, Function) 不存在则计算添加");
System.out.println(" computeIfPresent(K, BiFunction) 存在则更新");
System.out.println(" compute(K, BiFunction) 重新计算");
System.out.println(" merge(K, V, BiFunction) 合并值");
System.out.println(" replaceAll(BiFunction) 批量替换");
System.out.println();
}
/**
* 批量操作
*/
private static void bulkOperations() {
System.out.println("【批量操作】\n");
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
for (int i = 0; i < 10; i++) {
map.put("key" + i, i);
}
// forEach - 遍历
System.out.println("forEach:");
map.forEach((k, v) -> System.out.print(v + " "));
System.out.println();
// forEach带并行度
System.out.println("\nforEach并行遍历:");
map.forEach(2, (k, v) -> System.out.print(Thread.currentThread().getName() + ":" + v + " "));
System.out.println();
// search - 搜索
Integer result = map.search(2, (k, v) -> v > 5 ? v : null);
System.out.println("\nsearch结果: " + result);
// reduce - 归约
Integer sum = map.reduce(2, (k, v) -> v, Integer::sum);
System.out.println("reduce求和: " + sum);
// reduceValues - 只归约值
Integer max = map.reduceValues(2, Integer::max);
System.out.println("reduceValues求最大值: " + max);
System.out.println();
System.out.println("批量操作特点:");
System.out.println(" - 支持并行处理");
System.out.println(" - 可指定并行度");
System.out.println(" - 操作期间不影响其他操作");
System.out.println(" - 弱一致性:不保证反映最新修改");
System.out.println();
}
}
2.1.2 ConcurrentHashMap原理
java
/**
* ConcurrentHashMap实现原理
*/
public class ConcurrentHashMapPrincipleDemo {
public static void main(String[] args) {
System.out.println("=== ConcurrentHashMap原理 ===\n");
jdk7Implementation();
jdk8Implementation();
comparison();
}
/**
* JDK 7实现(分段锁)
*/
private static void jdk7Implementation() {
System.out.println("【JDK 7: 分段锁实现】\n");
/*
JDK 7的ConcurrentHashMap采用分段锁(Segment)设计
结构:
┌─────────────────────────────────────────────────────────────┐
│ ConcurrentHashMap │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │Segment 0│ │Segment 1│ │Segment 2│ │Segment n│ ... │
│ │ (锁) │ │ (锁) │ │ (锁) │ │ (锁) │ │
│ └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘ │
│ │ │ │ │ │
│ ▼ ▼ ▼ ▼ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ HashEntry│ │ HashEntry│ │ HashEntry│ │ HashEntry│ │
│ │ 链表 │ │ 链表 │ │ 链表 │ │ 链表 │ │
│ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
特点:
1. 默认16个Segment
2. 每个Segment是一个小型的HashMap
3. 每个Segment有自己的锁
4. 不同Segment的操作可以并发
5. 同一Segment的操作需要竞争锁
*/
System.out.println("分段锁特点:");
System.out.println(" - Segment继承ReentrantLock");
System.out.println(" - 默认16个Segment");
System.out.println(" - 并发度 = Segment数量");
System.out.println(" - put操作只锁一个Segment");
System.out.println(" - size()需要锁所有Segment");
System.out.println();
System.out.println("问题:");
System.out.println(" - 并发度受Segment数量限制");
System.out.println(" - size()操作开销大");
System.out.println(" - 内存占用较大");
System.out.println();
}
/**
* JDK 8实现(CAS + synchronized)
*/
private static void jdk8Implementation() {
System.out.println("【JDK 8: CAS + synchronized实现】\n");
/*
JDK 8的ConcurrentHashMap放弃分段锁,采用更细粒度的锁
结构:
┌─────────────────────────────────────────────────────────────┐
│ ConcurrentHashMap │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┐ │
│ │ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │... │ 15 │ │
│ └──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴────┴────┘ │
│ │ │ │ │ │ │ │ │
│ ▼ ▼ ▼ ▼ ▼ ▼ ▼ │
│ Node Node null Node null Node TreeBin │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ Node Node 红黑树 │
│ │ │ │
│ ▼ ▼ │
│ Node Node │
│ │
│ 重要节点类型: │
│ - Node: 普通链表节点 │
│ - TreeBin: 红黑树头节点(链表长度>8时转换) │
│ - ForwardingNode: 扩容转发节点 │
│ - ReservationNode: 占位节点 │
│ │
└─────────────────────────────────────────────────────────────┘
*/
System.out.println("JDK 8改进:");
System.out.println(" - 取消Segment,使用Node数组");
System.out.println(" - 使用CAS + synchronized");
System.out.println(" - 锁粒度更细(每个桶)");
System.out.println(" - 并发度更高");
System.out.println();
System.out.println("put操作流程:");
System.out.println(" 1. 计算hash,定位桶");
System.out.println(" 2. 桶为空: CAS插入新节点");
System.out.println(" 3. 桶不为空: synchronized锁桶头节点");
System.out.println(" 4. 链表遍历插入/更新");
System.out.println(" 5. 链表长度>8: 转红黑树");
System.out.println();
System.out.println("扩容机制:");
System.out.println(" - 多线程协同扩容");
System.out.println(" - 每个线程负责一部分桶");
System.out.println(" - ForwardingNode标记已迁移桶");
System.out.println(" - 扩容期间可正常读写");
System.out.println();
System.out.println("size计数:");
System.out.println(" - baseCount基础计数");
System.out.println(" - CounterCell数组分散计数");
System.out.println(" - LongAdder思想");
System.out.println(" - 最终size = baseCount + 所有CounterCell");
System.out.println();
}
/**
* 版本对比
*/
private static void comparison() {
System.out.println("【版本对比】\n");
System.out.println("┌─────────────────┬──────────────────┬──────────────────┐");
System.out.println("│ 特性 │ JDK 7 │ JDK 8 │");
System.out.println("├─────────────────┼──────────────────┼──────────────────┤");
System.out.println("│ 锁机制 │ 分段锁 │ CAS+synchronized │");
System.out.println("│ 锁粒度 │ Segment │ 桶(Node) │");
System.out.println("│ 并发度 │ 固定(默认16) │ 动态(桶数量) │");
System.out.println("│ 哈希冲突 │ 链表 │ 链表+红黑树 │");
System.out.println("│ 扩容 │ 单线程 │ 多线程协同 │");
System.out.println("│ size() │ 锁所有Segment │ 无锁累加 │");
System.out.println("│ 内存占用 │ 较大 │ 较小 │");
System.out.println("└─────────────────┴──────────────────┴──────────────────┘");
System.out.println();
}
}
2.2 CopyOnWrite容器
java
import java.util.*;
import java.util.concurrent.*;
/**
* CopyOnWrite容器详解
*/
public class CopyOnWriteDemo {
public static void main(String[] args) {
System.out.println("=== CopyOnWrite容器 ===\n");
copyOnWriteArrayList();
copyOnWriteArraySet();
useCases();
}
/**
* CopyOnWriteArrayList
*/
private static void copyOnWriteArrayList() {
System.out.println("【CopyOnWriteArrayList】\n");
CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
// 添加元素
list.add("A");
list.add("B");
list.add("C");
System.out.println("初始列表: " + list);
// 迭代期间修改
System.out.println("\n迭代期间修改:");
for (String s : list) {
System.out.println("读取: " + s);
if (s.equals("B")) {
list.add("D"); // 不会抛出ConcurrentModificationException
System.out.println(" 添加D(创建新数组)");
}
}
System.out.println("迭代后列表: " + list);
System.out.println();
/*
CopyOnWrite原理:
写操作时:
┌─────────────────────────────────────────────────────────────┐
│ │
│ 原数组 ──► 复制 ──► 新数组 ──► 修改 ──► 引用指向新数组 │
│ [A,B,C] 复制 [A,B,C] 添加D [A,B,C,D] │
│ │
│ 读操作: 直接读取原数组引用(无需加锁) │
│ 写操作: 复制新数组,修改后替换引用(加锁) │
│ │
└─────────────────────────────────────────────────────────────┘
*/
System.out.println("特点:");
System.out.println(" - 写时复制");
System.out.println(" - 读操作无锁");
System.out.println(" - 写操作需要复制整个数组");
System.out.println(" - 迭代器不会抛出ConcurrentModificationException");
System.out.println(" - 迭代器遍历的是创建时的快照");
System.out.println();
}
/**
* CopyOnWriteArraySet
*/
private static void copyOnWriteArraySet() {
System.out.println("【CopyOnWriteArraySet】\n");
CopyOnWriteArraySet<String> set = new CopyOnWriteArraySet<>();
set.add("A");
set.add("B");
set.add("A"); // 重复元素不会添加
set.add("C");
System.out.println("Set内容: " + set);
System.out.println();
System.out.println("说明:");
System.out.println(" - 内部使用CopyOnWriteArrayList实现");
System.out.println(" - 添加时检查是否已存在");
System.out.println(" - 性能比CopyOnWriteArrayList稍差(需要遍历检查)");
System.out.println();
}
/**
* 使用场景
*/
private static void useCases() {
System.out.println("【使用场景分析】\n");
System.out.println("✅ 适用场景:");
System.out.println(" 1. 读多写少");
System.out.println(" 2. 迭代远多于修改");
System.out.println(" 3. 需要保证迭代时不抛出异常");
System.out.println(" 4. 监听器列表、事件处理器列表");
System.out.println();
System.out.println("❌ 不适用场景:");
System.out.println(" 1. 写操作频繁");
System.out.println(" 2. 列表数据量大(复制开销大)");
System.out.println(" 3. 对实时性要求高(读写可能不一致)");
System.out.println(" 4. 需要保证写操作原子性");
System.out.println();
System.out.println("示例: 事件监听器管理");
System.out.println("""
class EventSource {
private final CopyOnWriteArrayList<EventListener> listeners =
new CopyOnWriteArrayList<>();
public void addListener(EventListener listener) {
listeners.add(listener); // 写时复制
}
public void fireEvent(Event event) {
for (EventListener listener : listeners) { // 无锁遍历
listener.onEvent(event);
}
}
}
""");
System.out.println("内存开销:");
System.out.println(" - 每次写操作都创建新数组");
System.out.println(" - 内存占用 = 数据大小 × 写操作次数");
System.out.println(" - 频繁写操作会导致内存压力");
System.out.println();
}
}
2.3 阻塞队列
2.3.1 阻塞队列基础
java
import java.util.*;
import java.util.concurrent.*;
/**
* 阻塞队列详解
*/
public class BlockingQueueDemo {
public static void main(String[] args) throws InterruptedException {
System.out.println("=== 阻塞队列详解 ===\n");
basicOperations();
arrayBlockingQueue();
linkedBlockingQueue();
priorityBlockingQueue();
delayQueue();
synchronousQueue();
}
/**
* 基本操作
*/
private static void basicOperations() {
System.out.println("【阻塞队列基本操作】\n");
System.out.println("插入操作:");
System.out.println(" add(e) 插入元素,满则抛异常");
System.out.println(" offer(e) 插入元素,满则返回false");
System.out.println(" offer(e, t) 超时插入,满则等待");
System.out.println(" put(e) 插入元素,满则阻塞");
System.out.println();
System.out.println("移除操作:");
System.out.println(" remove() 移除元素,空则抛异常");
System.out.println(" poll() 移除元素,空则返回null");
System.out.println(" poll(t) 超时移除,空则等待");
System.out.println(" take() 移除元素,空则阻塞");
System.out.println();
System.out.println("检查操作:");
System.out.println(" element() 获取队首,空则抛异常");
System.out.println(" peek() 获取队首,空则返回null");
System.out.println();
}
/**
* ArrayBlockingQueue
*/
private static void arrayBlockingQueue() throws InterruptedException {
System.out.println("【ArrayBlockingQueue】\n");
// 有界数组阻塞队列
ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<>(3);
// 公平队列(可选)
ArrayBlockingQueue<String> fairQueue = new ArrayBlockingQueue<>(3, true);
System.out.println("添加元素:");
System.out.println(" offer('A'): " + queue.offer("A"));
System.out.println(" offer('B'): " + queue.offer("B"));
System.out.println(" offer('C'): " + queue.offer("C"));
System.out.println(" offer('D'): " + queue.offer("D")); // 返回false
System.out.println("队列: " + queue);
System.out.println("\ntake操作:");
System.out.println(" take(): " + queue.take());
System.out.println("队列: " + queue);
System.out.println();
System.out.println("特点:");
System.out.println(" - 有界队列(必须指定容量)");
System.out.println(" - 底层是数组");
System.out.println(" - 可选择公平/非公平");
System.out.println(" - 使用一把ReentrantLock");
System.out.println(" - 读写共用一把锁");
System.out.println();
}
/**
* LinkedBlockingQueue
*/
private static void linkedBlockingQueue() {
System.out.println("【LinkedBlockingQueue】\n");
// 可选有界链表阻塞队列
LinkedBlockingQueue<String> queue = new LinkedBlockingQueue<>(); // 无界(Integer.MAX_VALUE)
LinkedBlockingQueue<String> boundedQueue = new LinkedBlockingQueue<>(100); // 有界
queue.offer("A");
queue.offer("B");
queue.offer("C");
System.out.println("队列: " + queue);
System.out.println("peek: " + queue.peek());
System.out.println("poll: " + queue.poll());
System.out.println("队列: " + queue);
System.out.println();
System.out.println("特点:");
System.out.println(" - 可选有界(默认Integer.MAX_VALUE)");
System.out.println(" - 底层是链表");
System.out.println(" - 使用两把ReentrantLock(takeLock和putLock)");
System.out.println(" - 读写可以并行");
System.out.println(" - 性能优于ArrayBlockingQueue");
System.out.println();
System.out.println("对比ArrayBlockingQueue:");
System.out.println(" ┌───────────────┬─────────────────┬─────────────────┐");
System.out.println(" │ 特性 │ ArrayBlockingQ │ LinkedBlockingQ │");
System.out.println(" ├───────────────┼─────────────────┼─────────────────┤");
System.out.println(" │ 底层结构 │ 数组 │ 链表 │");
System.out.println(" │ 容量 │ 必须指定 │ 可选(默认无限)│");
System.out.println(" │ 锁数量 │ 1把 │ 2把 │");
System.out.println(" │ 读写并发 │ 不可以 │ 可以 │");
System.out.println(" │ 内存占用 │ 连续 │ 分散 │");
System.out.println(" └───────────────┴─────────────────┴─────────────────┘");
System.out.println();
}
/**
* PriorityBlockingQueue
*/
private static void priorityBlockingQueue() {
System.out.println("【PriorityBlockingQueue】\n");
// 无界优先级阻塞队列
PriorityBlockingQueue<Integer> queue = new PriorityBlockingQueue<>();
// 自定义比较器
PriorityBlockingQueue<String> customQueue = new PriorityBlockingQueue<>(
11, Comparator.reverseOrder()
);
queue.offer(5);
queue.offer(1);
queue.offer(3);
queue.offer(2);
queue.offer(4);
System.out.println("队列(堆结构): " + queue);
System.out.println("\n按优先级出队:");
while (!queue.isEmpty()) {
System.out.print(queue.poll() + " ");
}
System.out.println();
System.out.println();
System.out.println("特点:");
System.out.println(" - 无界队列(自动扩容)");
System.out.println(" - 基于二叉堆实现");
System.out.println(" - 元素必须实现Comparable或提供Comparator");
System.out.println(" - 出队顺序按优先级(默认最小堆)");
System.out.println(" - 不保证同优先级元素的顺序");
System.out.println();
}
/**
* DelayQueue
*/
private static void delayQueue() throws InterruptedException {
System.out.println("【DelayQueue】\n");
class DelayedTask implements Delayed {
private final String name;
private final long executeTime;
public DelayedTask(String name, long delayMillis) {
this.name = name;
this.executeTime = System.currentTimeMillis() + delayMillis;
}
@Override
public long getDelay(TimeUnit unit) {
long diff = executeTime - System.currentTimeMillis();
return unit.convert(diff, TimeUnit.MILLISECONDS);
}
@Override
public int compareTo(Delayed o) {
return Long.compare(this.executeTime, ((DelayedTask) o).executeTime);
}
@Override
public String toString() {
return name;
}
}
DelayQueue<DelayedTask> queue = new DelayQueue<>();
// 添加延迟任务
queue.offer(new DelayedTask("任务C", 3000));
queue.offer(new DelayedTask("任务A", 1000));
queue.offer(new DelayedTask("任务B", 2000));
System.out.println("等待任务执行...");
// 按延迟时间取出
for (int i = 0; i < 3; i++) {
DelayedTask task = queue.take();
System.out.println("执行: " + task + ", 时间: " + System.currentTimeMillis());
}
System.out.println();
System.out.println("特点:");
System.out.println(" - 无界阻塞队列");
System.out.println(" - 元素必须实现Delayed接口");
System.out.println(" - 只有到期元素才能被取出");
System.out.println(" - 按延迟时间排序");
System.out.println();
System.out.println("应用场景:");
System.out.println(" - 定时任务调度");
System.out.println(" - 缓存过期清理");
System.out.println(" - 订单超时取消");
System.out.println();
}
/**
* SynchronousQueue
*/
private static void synchronousQueue() throws InterruptedException {
System.out.println("【SynchronousQueue】\n");
SynchronousQueue<String> queue = new SynchronousQueue<>();
// 生产者线程
Thread producer = new Thread(() -> {
try {
System.out.println("生产者: 尝试放入A");
queue.put("A");
System.out.println("生产者: A已被消费");
Thread.sleep(100);
System.out.println("生产者: 尝试放入B");
queue.put("B");
System.out.println("生产者: B已被消费");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
// 消费者线程
Thread consumer = new Thread(() -> {
try {
Thread.sleep(500); // 让生产者先等待
System.out.println("消费者: 尝试获取");
String item = queue.take();
System.out.println("消费者: 获取到 " + item);
Thread.sleep(500);
System.out.println("消费者: 尝试获取");
item = queue.take();
System.out.println("消费者: 获取到 " + item);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
producer.start();
consumer.start();
producer.join();
consumer.join();
System.out.println();
System.out.println("特点:");
System.out.println(" - 零容量(不存储元素)");
System.out.println(" - put操作必须等待take");
System.out.println(" - 每个插入操作必须等待对应移除操作");
System.out.println(" - 可选公平/非公平模式");
System.out.println();
System.out.println("应用场景:");
System.out.println(" - 线程池(Executors.newCachedThreadPool)");
System.out.println(" - 任务直接传递");
System.out.println(" - 生产者消费者直接交接");
System.out.println();
}
}
2.3.2 阻塞队列应用
java
import java.util.concurrent.*;
/**
* 阻塞队列应用示例
*/
public class BlockingQueueApplicationDemo {
public static void main(String[] args) throws InterruptedException {
System.out.println("=== 阻塞队列应用 ===\n");
producerConsumerPattern();
threadPoolWithQueue();
}
/**
* 生产者-消费者模式
*/
private static void producerConsumerPattern() throws InterruptedException {
System.out.println("【生产者-消费者模式】\n");
ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<>(5);
// 生产者
Thread producer = new Thread(() -> {
String[] items = {"A", "B", "C", "D", "E", "F", "G", "H"};
for (String item : items) {
try {
queue.put(item);
System.out.println("生产: " + item + " (队列大小: " + queue.size() + ")");
Thread.sleep(100);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
}
System.out.println("生产者结束");
}, "Producer");
// 消费者
Thread consumer = new Thread(() -> {
int count = 0;
while (count < 8) {
try {
String item = queue.take();
System.out.println(" 消费: " + item + " (队列大小: " + queue.size() + ")");
Thread.sleep(200);
count++;
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
}
System.out.println("消费者结束");
}, "Consumer");
producer.start();
consumer.start();
producer.join();
consumer.join();
System.out.println();
}
/**
* 线程池中的队列选择
*/
private static void threadPoolWithQueue() {
System.out.println("【线程池队列选择】\n");
System.out.println("1. FixedThreadPool - LinkedBlockingQueue");
System.out.println(" ExecutorService pool = Executors.newFixedThreadPool(10);");
System.out.println(" 特点: 无界队列,可能导致OOM");
System.out.println();
System.out.println("2. CachedThreadPool - SynchronousQueue");
System.out.println(" ExecutorService pool = Executors.newCachedThreadPool();");
System.out.println(" 特点: 零容量,直接传递,线程数可能无限增长");
System.out.println();
System.out.println("3. SingleThreadExecutor - LinkedBlockingQueue");
System.out.println(" ExecutorService pool = Executors.newSingleThreadExecutor();");
System.out.println(" 特点: 无界队列,单线程顺序执行");
System.out.println();
System.out.println("4. ScheduledThreadPool - DelayedWorkQueue");
System.out.println(" ScheduledExecutorService pool = Executors.newScheduledThreadPool(5);");
System.out.println(" 特点: 延迟队列,支持定时和周期任务");
System.out.println();
System.out.println("5. 自定义线程池 - 自定义队列");
System.out.println("""
ThreadPoolExecutor pool = new ThreadPoolExecutor(
corePoolSize, // 核心线程数
maximumPoolSize, // 最大线程数
keepAliveTime, // 空闲线程存活时间
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(100), // 有界队列
new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略
);
""");
System.out.println();
System.out.println("队列选择建议:");
System.out.println(" - 有界队列: 防止资源耗尽,需要合理设置拒绝策略");
System.out.println(" - 无界队列: 简单,但可能导致OOM");
System.out.println(" - 同步移交: 高吞吐量,但线程数可能增长");
System.out.println();
}
}
三、可运行Java代码示例
完整示例:并发缓存
java
import java.util.*;
import java.util.concurrent.*;
/**
* 并发缓存完整示例
*/
public class ConcurrentCacheDemo {
public static void main(String[] args) throws InterruptedException {
System.out.println("=== 并发缓存示例 ===\n");
// 简单缓存
testSimpleCache();
// 带过期的缓存
testExpiringCache();
}
/**
* 简单并发缓存
*/
private static void testSimpleCache() throws InterruptedException {
System.out.println("【简单并发缓存】\n");
class ConcurrentCache<K, V> {
private final ConcurrentHashMap<K, V> cache = new ConcurrentHashMap<>();
public V get(K key) {
return cache.get(key);
}
public void put(K key, V value) {
cache.put(key, value);
}
public V computeIfAbsent(K key, Function<K, V> loader) {
return cache.computeIfAbsent(key, loader);
}
public void remove(K key) {
cache.remove(key);
}
public void clear() {
cache.clear();
}
public int size() {
return cache.size();
}
public boolean containsKey(K key) {
return cache.containsKey(key);
}
}
ConcurrentCache<String, String> cache = new ConcurrentCache<>();
// 多线程测试
int threadCount = 10;
CountDownLatch latch = new CountDownLatch(threadCount);
for (int i = 0; i < threadCount; i++) {
final int index = i;
new Thread(() -> {
String key = "key" + index;
cache.computeIfAbsent(key, k -> {
System.out.println("加载: " + k);
return "value" + index;
});
System.out.println("获取: " + key + " = " + cache.get(key));
latch.countDown();
}).start();
}
latch.await();
System.out.println("缓存大小: " + cache.size());
System.out.println();
}
/**
* 带过期的缓存
*/
private static void testExpiringCache() throws InterruptedException {
System.out.println("【带过期的缓存】\n");
class ExpiringCache<K, V> {
private final ConcurrentHashMap<K, CacheEntry<V>> cache = new ConcurrentHashMap<>();
private final DelayQueue<ExpiryKey<K>> expiryQueue = new DelayQueue<>();
private final Thread cleanerThread;
static class CacheEntry<V> {
final V value;
final long expiryTime;
CacheEntry(V value, long expiryTime) {
this.value = value;
this.expiryTime = expiryTime;
}
}
static class ExpiryKey<K> implements Delayed {
final K key;
final long expiryTime;
ExpiryKey(K key, long expiryTime) {
this.key = key;
this.expiryTime = expiryTime;
}
@Override
public long getDelay(TimeUnit unit) {
return unit.convert(expiryTime - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
}
@Override
public int compareTo(Delayed o) {
return Long.compare(expiryTime, ((ExpiryKey<?>) o).expiryTime);
}
}
public ExpiringCache() {
cleanerThread = new Thread(() -> {
while (!Thread.currentThread().isInterrupted()) {
try {
ExpiryKey<K> key = expiryQueue.take();
cache.remove(key.key);
System.out.println("过期清理: " + key.key);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
});
cleanerThread.setDaemon(true);
cleanerThread.start();
}
public void put(K key, V value, long ttlMillis) {
long expiryTime = System.currentTimeMillis() + ttlMillis;
cache.put(key, new CacheEntry<>(value, expiryTime));
expiryQueue.offer(new ExpiryKey<>(key, expiryTime));
}
public V get(K key) {
CacheEntry<V> entry = cache.get(key);
if (entry == null || entry.expiryTime < System.currentTimeMillis()) {
cache.remove(key);
return null;
}
return entry.value;
}
public void shutdown() {
cleanerThread.interrupt();
}
}
ExpiringCache<String, String> cache = new ExpiringCache<>();
// 添加缓存,2秒过期
cache.put("key1", "value1", 2000);
cache.put("key2", "value2", 4000);
System.out.println("立即获取: " + cache.get("key1"));
Thread.sleep(3000);
System.out.println("3秒后获取key1: " + cache.get("key1")); // null
System.out.println("3秒后获取key2: " + cache.get("key2")); // value2
Thread.sleep(2000);
System.out.println("5秒后获取key2: " + cache.get("key2")); // null
cache.shutdown();
System.out.println();
}
}
四、总结与最佳实践
核心要点回顾
| 容器类型 | 特点 | 适用场景 |
|---|---|---|
| ConcurrentHashMap | 分段锁/CAS,高并发 | 并发Map操作 |
| CopyOnWriteArrayList | 写时复制 | 读多写少 |
| ArrayBlockingQueue | 有界,单锁 | 生产者-消费者 |
| LinkedBlockingQueue | 可选有界,双锁 | 高吞吐量队列 |
| PriorityBlockingQueue | 无界,优先级 | 优先级任务调度 |
| DelayQueue | 延迟队列 | 定时任务 |
| SynchronousQueue | 零容量 | 直接传递 |
最佳实践
-
选择合适的容器
- 并发Map用ConcurrentHashMap
- 读多写少用CopyOnWrite
- 生产者-消费者用BlockingQueue
-
避免同步集合
- 不推荐使用Collections.synchronizedXxx
- 使用并发容器替代
-
注意容量限制
- 无界队列可能导致OOM
- 有界队列需要处理拒绝情况
-
理解弱一致性
- 迭代器不保证反映最新修改
- size()等方法不保证精确
扩展阅读
- 《Java并发编程实战》:并发容器章节
- 《Java并发编程的艺术》:ConcurrentHashMap原理
- JDK源码:java.util.concurrent包