轩辕李的博客 轩辕李的博客
首页
  • Java
  • Spring
  • 其他语言
  • 工具
  • HTML&CSS
  • JavaScript
  • 分布式
  • 代码质量管理
  • 基础
  • 操作系统
  • 计算机网络
  • 编程范式
  • 安全
  • 中间件
  • 心得
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

轩辕李

勇猛精进,星辰大海
首页
  • Java
  • Spring
  • 其他语言
  • 工具
  • HTML&CSS
  • JavaScript
  • 分布式
  • 代码质量管理
  • 基础
  • 操作系统
  • 计算机网络
  • 编程范式
  • 安全
  • 中间件
  • 心得
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • Java

    • 核心

    • 并发

      • Java并发-线程基础与synchronized关键字
      • Java并发-重入锁ReentrantLock详解与实践
      • Java并发-信号量Semaphore
      • Java并发-读写锁ReadWriteLock
      • Java并发-倒计时器CountDownLatch
      • Java并发-栅栏CyclicBarrier
      • Java并发-LockSupport线程阻塞工具类
      • Java并发-线程池ThreadPoolExecutor
      • Java并发-阻塞队列BlockingQueue
      • Java并发-以空间换时间之ThreadLocal
      • Java并发-无锁策略CAS与atomic包
      • Java并发-JDK并发容器
        • 一、旧时代的同步容器
        • 二、新时代的并发容器
          • 1、非阻塞队列
          • 2、写时复制容器
          • 3、阻塞队列
          • 4、并发Map
        • 三、核心设计思想
          • 1、分段锁(Segment Locking)
          • 2、写时复制(Copy-On-Write)
          • 3、非阻塞算法
        • 四、使用示例
          • 1、ConcurrentHashMap示例
          • 2、CopyOnWriteArrayList示例
          • 3、BlockingQueue示例
        • 五、选择建议
        • 六、分布式集合
        • 七、总结
      • Java并发-异步调用结果之Future和CompletableFuture
      • Java并发-Fork Join框架
      • Java并发-调试与诊断
    • 经验

    • JVM

    • 企业应用

  • Spring

  • 其他语言

  • 工具

  • 后端
  • Java
  • 并发
轩辕李
2021-12-14
目录

Java并发-JDK并发容器

并发编程中,会使用到容器类。JDK本身提供了一些常用且基础的容器类,很有必要了解一下。

# 一、旧时代的同步容器

在Java 1.5之前,线程安全的容器类实现相对简单,性能方面也差强人意,但我们还是要了解一下。

  • Vector。线程安全的ArrayList,所有方法都用synchronized修饰,达到线程安全的目的
  • HashTable。线程安全的HashMap,所有方法都用synchronized修饰,达到线程安全的目的
  • Collections.synchronizedXxx工厂方法。返回的容器类内部使用synchronized关键字实现线程安全

# 二、新时代的并发容器

Java 1.5之后,利用CAS指令(乐观锁)提供了更高效的并发容器。

# 1、非阻塞队列

  • ConcurrentLinkedQueue。基于链表的无界线程安全队列,采用非阻塞算法,高并发环境下性能最好的队列。适用场景:高并发的生产者-消费者模型,不需要阻塞等待的场景

# 2、写时复制容器

  • CopyOnWriteArrayList。只在写时加锁的ArrayList,采用写时复制(Copy-On-Write)的思想,读性能大幅提升。适用场景:读多写少的场景,如配置、黑白名单等
  • CopyOnWriteArraySet。基于CopyOnWriteArrayList实现的Set,同样适用于读多写少的场景

# 3、阻塞队列

  • BlockingQueue。一个阻塞式的数据共享通道,参考:阻塞队列BlockingQueue。主要实现有:
    • ArrayBlockingQueue。基于数组的有界阻塞队列,必须指定容量
    • LinkedBlockingQueue。基于链表的可选有界阻塞队列,不指定容量时为Integer.MAX_VALUE
    • LinkedBlockingDeque。基于链表的双向阻塞队列,支持从两端插入和移除元素
    • PriorityBlockingQueue。支持优先级排序的无界阻塞队列
    • DelayQueue。支持延迟获取元素的无界阻塞队列
    • SynchronousQueue。不存储元素的阻塞队列,每个插入操作必须等待另一个线程的移除操作

# 4、并发Map

  • ConcurrentMap。线程安全的Map接口,主要实现有:
    • ConcurrentHashMap。高并发哈希表,采用分段锁(JDK 1.7)或CAS+synchronized(JDK 1.8+)实现,适用于高并发的键值对存储
    • ConcurrentSkipListMap。基于跳表实现的有序并发Map,提供有序的遍历。相比TreeMap的红黑树实现,跳表的插入和删除只需要对局部数据进行操作,避免了全局锁的使用

# 三、核心设计思想

# 1、分段锁(Segment Locking)

ConcurrentHashMap在JDK 1.7中利用了分而治之的思想,使用分段锁(Segment)技术。将整个哈希表分为多个段,每个段独立加锁,这样不同段的操作可以并发进行,大大提高了并发性能。JDK 1.8之后改为使用CAS操作和synchronized锁定桶头节点,进一步优化了性能。

# 2、写时复制(Copy-On-Write)

CopyOnWriteArrayList采用了写时复制的思想:

  • 读操作不加锁,直接读取当前数组
  • 写操作会复制一份新的数组,在新数组上修改,然后将引用指向新数组
  • 在迭代频率远高于容器修改时,性能大大增强
  • 缺点是内存占用较大,且数据一致性是最终一致性

# 3、非阻塞算法

ConcurrentLinkedQueue使用非阻塞算法(lock-free),基于CAS操作实现线程安全,避免了锁的开销,在高并发场景下性能优异。

# 四、使用示例

# 1、ConcurrentHashMap示例

ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
// 线程安全的put操作
map.put("key1", 1);
// 原子性的putIfAbsent
map.putIfAbsent("key2", 2);
// 原子性的replace
map.replace("key1", 1, 10);
// 并发遍历
map.forEach((k, v) -> System.out.println(k + ": " + v));

# 2、CopyOnWriteArrayList示例

CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
// 写操作会复制整个数组
list.add("item1");
// 读操作不加锁
String item = list.get(0);
// 迭代器是快照,不会抛出ConcurrentModificationException
for (String s : list) {
    list.add("newItem"); // 不会影响当前迭代
}

# 3、BlockingQueue示例

BlockingQueue<String> queue = new LinkedBlockingQueue<>(100);
// 生产者
queue.put("item"); // 队列满时阻塞
queue.offer("item", 5, TimeUnit.SECONDS); // 超时等待
// 消费者
String item = queue.take(); // 队列空时阻塞
String item2 = queue.poll(5, TimeUnit.SECONDS); // 超时等待

# 五、选择建议

  1. 读多写少场景:使用CopyOnWriteArrayList或CopyOnWriteArraySet
  2. 高并发键值对存储:使用ConcurrentHashMap
  3. 需要有序遍历的并发Map:使用ConcurrentSkipListMap
  4. 生产者-消费者模型:
    • 需要阻塞:使用BlockingQueue的各种实现
    • 不需要阻塞:使用ConcurrentLinkedQueue
  5. 任务调度:使用DelayQueue或PriorityBlockingQueue

# 六、分布式集合

分布式环境下要使用集合,可以考虑Redisson (opens new window)。
我在Java集合文章中有所介绍,请移步查看。

# 七、总结

工欲善其事,必先利其器。新时代的Java并发容器能较好且安全地解决多线程并发问题,需要好好地掌握它!

祝你变得更强!

编辑 (opens new window)
上次更新: 2025/08/15
Java并发-无锁策略CAS与atomic包
Java并发-异步调用结果之Future和CompletableFuture

← Java并发-无锁策略CAS与atomic包 Java并发-异步调用结果之Future和CompletableFuture→

最近更新
01
AI时代的编程心得
09-11
02
Claude Code与Codex的协同工作
09-01
03
Claude Code实战之供应商切换工具
08-18
更多文章>
Theme by Vdoing | Copyright © 2018-2025 京ICP备2021021832号-2 | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式