Skip to content

并发集合

Java 提供了线程安全的并发集合类,用于替代传统的集合类在多线程环境中的使用。

1. ConcurrentHashMap

线程安全的 HashMap,采用分段锁(JDK 7)或 CAS + synchronized(JDK 8+)实现。

1.1 基本用法

java
import java.util.concurrent.*;

ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();

// 基本操作
map.put("key", 1);
Integer value = map.get("key");
map.remove("key");

1.2 原子操作

java
// putIfAbsent:不存在才放入
map.putIfAbsent("key", 2);

// computeIfAbsent:不存在才计算并放入
map.computeIfAbsent("key2", k -> expensiveComputation(k));

// computeIfPresent:存在才计算并更新
map.computeIfPresent("key", (k, v) -> v + 1);

// merge:合并值
map.merge("key", 5, Integer::sum);

// getOrDefault:不存在返回默认值
int val = map.getOrDefault("key", 0);

1.3 与 Hashtable 对比

特性ConcurrentHashMapHashtable
锁粒度分段锁/CAS整个表加锁
性能
允许 null key/value
迭代器弱一致性快速失败

1.4 适用场景

  • 高并发读写的缓存
  • 计数器
  • 共享配置
java
// 统计访问次数
ConcurrentHashMap<String, AtomicLong> counter = new ConcurrentHashMap<>();

public void recordAccess(String url) {
    counter.computeIfAbsent(url, k -> new AtomicLong(0))
           .incrementAndGet();
}

2. CopyOnWriteArrayList

适合读多写少的场景,写时复制整个数组。

2.1 基本用法

java
import java.util.concurrent.*;

CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
list.add("item1");
list.add("item2");

// 遍历时修改不会抛出 ConcurrentModificationException
for (String item : list) {
    if (item.equals("item1")) {
        list.add("item3"); // 安全操作
    }
}

2.2 工作原理

写操作:
┌─────────────────┐     复制      ┌─────────────────┐
│ 原始数组 [A,B,C]│  ───────────► │ 新数组 [A,B,C,D]│
└─────────────────┘               └─────────────────┘


                                  引用指向新数组

读操作:
直接读取当前数组,无需加锁

2.3 适用场景

  • 监听器列表
  • 配置项列表
  • 黑白名单

⚠️ 注意:写操作开销大,不适合频繁写入的场景。


3. CopyOnWriteArraySet

基于 CopyOnWriteArrayList 实现的 Set。

java
CopyOnWriteArraySet<String> set = new CopyOnWriteArraySet<>();
set.add("a");
set.add("b");
set.add("a"); // 不会重复添加

4. BlockingQueue

阻塞队列,常用于生产者-消费者模式

4.1 常见实现

实现类特点
ArrayBlockingQueue有界数组队列
LinkedBlockingQueue可选有界链表队列
PriorityBlockingQueue优先级队列
SynchronousQueue不存储元素的队列
DelayQueue延迟队列

4.2 核心方法

操作抛异常返回特殊值阻塞超时
插入add(e)offer(e)put(e)offer(e,time,unit)
移除remove()poll()take()poll(time,unit)
检查element()peek()--

4.3 生产者-消费者示例

java
import java.util.concurrent.*;

public class ProducerConsumerDemo {
    public static void main(String[] args) {
        BlockingQueue<String> queue = new ArrayBlockingQueue<>(10);
        
        // 生产者
        new Thread(() -> {
            try {
                for (int i = 0; i < 20; i++) {
                    queue.put("消息" + i);  // 队列满时阻塞
                    System.out.println("生产: 消息" + i);
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }).start();
        
        // 消费者
        new Thread(() -> {
            try {
                while (true) {
                    String msg = queue.take();  // 队列空时阻塞
                    System.out.println("消费: " + msg);
                    Thread.sleep(500);
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }).start();
    }
}

5. ConcurrentLinkedQueue

无锁的线程安全队列,基于 CAS 实现。

java
ConcurrentLinkedQueue<String> queue = new ConcurrentLinkedQueue<>();

queue.offer("a");
queue.offer("b");
String head = queue.poll();

适用场景

  • 高并发无界队列
  • 不需要阻塞操作

6. ConcurrentSkipListMap

线程安全的有序 Map,基于跳表实现。

java
ConcurrentSkipListMap<String, Integer> map = new ConcurrentSkipListMap<>();

map.put("apple", 1);
map.put("banana", 2);
map.put("cherry", 3);

// 有序遍历
map.forEach((k, v) -> System.out.println(k + ": " + v));

// 范围查询
SortedMap<String, Integer> subMap = map.subMap("apple", "cherry");

7. 集合类选择指南

场景推荐类
高并发读写 MapConcurrentHashMap
有序并发 MapConcurrentSkipListMap
读多写少 ListCopyOnWriteArrayList
生产者消费者BlockingQueue
高并发无界队列ConcurrentLinkedQueue

性能对比

并发读写性能(从高到低):

ConcurrentHashMap

ConcurrentSkipListMap

Collections.synchronizedMap()

Hashtable