15-Java语言核心-并发编程-并发容器详解

并发容器详解

一、知识概述

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 零容量 直接传递

最佳实践

  1. 选择合适的容器

    • 并发Map用ConcurrentHashMap
    • 读多写少用CopyOnWrite
    • 生产者-消费者用BlockingQueue
  2. 避免同步集合

    • 不推荐使用Collections.synchronizedXxx
    • 使用并发容器替代
  3. 注意容量限制

    • 无界队列可能导致OOM
    • 有界队列需要处理拒绝情况
  4. 理解弱一致性

    • 迭代器不保证反映最新修改
    • size()等方法不保证精确

扩展阅读

  • 《Java并发编程实战》:并发容器章节
  • 《Java并发编程的艺术》:ConcurrentHashMap原理
  • JDK源码:java.util.concurrent包
相关推荐
xiaoliuliu123452 小时前
R语言4.5.0安装教程:详细步骤+自定义安装路径(64位)
开发语言·r语言
小宇的天下2 小时前
Calibre LVS Circuit Comparison(3)
开发语言·php·lvs
96772 小时前
多线程编程:整个互斥的流程以及scoped_lock的用法,以及作用,以及 硬件上的原子操作和逻辑上的原子操作
开发语言·c++·算法
liangblog2 小时前
Spring Boot中手动实例化 `JdbcTemplate` 并指定 数据源
java·spring boot·后端
liuyao_xianhui2 小时前
优选算法_topk问题_快速排序算法_堆_C++
java·开发语言·数据结构·c++·算法·链表·排序算法
liuyao_xianhui2 小时前
优选算法_堆_最后一块石头的重量_C++
java·开发语言·c++·算法·链表
好家伙VCC2 小时前
# 发散创新:基于状态通道的以太坊智能合约高效交互实践在区块链应用开发中,**交易
java·python·区块链·智能合约
羊小猪~~2 小时前
算法/力扣--栈与队列经典题目
开发语言·c++·后端·考研·算法·leetcode·职场和发展
Noushiki2 小时前
数据一致性保障方案 -java后端
java·开发语言