跳到主要内容

JUC 并发工具包简介

JUC(java.util.concurrent)是 Java 5 引入的并发工具包,它提供了一系列经过充分测试、高性能的并发构建块,极大简化了多线程编程的复杂度。在 JUC 出现之前,开发者只能依赖 synchronized 关键字和 wait/notify 机制来实现线程同步,这种方式不仅容易出错,而且性能有限。

为什么需要 JUC?

传统的 Java 并发编程存在以下问题:

synchronized 的局限性

synchronized 虽然使用简单,但功能有限。它无法中断一个正在等待锁的线程,无法设置锁的超时时间,也无法实现公平锁。当一个线程获取锁后,其他线程只能无限期等待。

线程管理的复杂性

在没有线程池之前,开发者需要手动创建和管理线程。线程是昂贵的系统资源,频繁创建和销毁线程会带来巨大的性能开销。同时,无限制地创建线程可能导致系统资源耗尽。

并发集合的缺失

传统的集合类(如 HashMap、ArrayList)不是线程安全的。虽然可以使用 Collections.synchronizedXXX 方法包装,但这种"全表锁"的方式并发性能很差。

原子操作的困难

实现线程安全的计数器、累加器等操作时,需要使用 synchronized,但这会带来锁竞争的开销。

JUC 的出现正是为了解决这些问题。它提供了更灵活的锁机制、高效的线程池、线程安全的并发集合以及无锁的原子操作类。

JUC 的组成

JUC 包含以下几个核心模块:

1. 锁机制(java.util.concurrent.locks)

提供比 synchronized 更灵活的锁操作:

  • ReentrantLock:可重入锁,支持公平/非公平模式、可中断锁、超时获取锁
  • ReentrantReadWriteLock:读写锁,允许多个读操作并行执行
  • StampedLock:Java 8 引入的乐观读写锁,性能更优
  • Condition:条件变量,替代 wait/notify 实现更精细的线程通信

2. 线程池框架(java.util.concurrent)

提供线程的复用和管理:

  • Executor:最基础的执行器接口
  • ExecutorService:扩展了 Executor,支持任务提交和关闭
  • ThreadPoolExecutor:线程池的核心实现类
  • ScheduledThreadPoolExecutor:支持定时和周期性任务执行
  • Executors:线程池工厂类,提供常用线程池的快捷创建方法

3. 并发集合(java.util.concurrent)

线程安全的集合实现:

  • ConcurrentHashMap:高性能的并发哈希表
  • CopyOnWriteArrayList:写时复制的线程安全 List
  • CopyOnWriteArraySet:写时复制的线程安全 Set
  • ConcurrentLinkedQueue:基于链表的无界并发队列
  • BlockingQueue 接口及其实现:ArrayBlockingQueue、LinkedBlockingQueue 等

4. 原子类(java.util.concurrent.atomic)

基于 CAS 实现的无锁线程安全操作:

  • 基本类型原子类:AtomicInteger、AtomicLong、AtomicBoolean
  • 引用类型原子类:AtomicReference、AtomicStampedReference
  • 数组类型原子类:AtomicIntegerArray、AtomicLongArray
  • 字段更新器:AtomicIntegerFieldUpdater 等
  • 累加器:LongAdder、DoubleAdder(高并发下性能优于 AtomicLong)

5. 同步工具类

用于协调多个线程的执行:

  • CountDownLatch:一次性栅栏,等待一组线程完成
  • CyclicBarrier:可循环使用的栅栏,让一组线程互相等待
  • Semaphore:信号量,控制并发访问数量
  • Exchanger:两个线程之间交换数据
  • Phaser:Java 7 引入,更灵活的同步屏障

6. Fork/Join 框架

Java 7 引入的并行计算框架,采用工作窃取算法,适合处理可递归分解的任务。

JUC 的设计理念

JUC 的设计遵循以下核心原则:

从悲观锁到乐观锁

传统的 synchronized 是悲观锁,假设会发生冲突,每次操作都加锁。JUC 中的原子类采用 CAS(Compare-And-Swap)乐观锁机制,假设不会发生冲突,只在更新时检查,失败后重试。

从全局锁到细粒度锁

Hashtable 使用全局锁,所有操作都串行执行。ConcurrentHashMap 在 JDK 7 中使用分段锁,JDK 8 进一步优化为桶级锁,大大提高了并发度。

从阻塞到非阻塞

传统的 wait/notify 是阻塞式的。JUC 提供了 LockSupport.park/unpark 等非阻塞机制,以及 Future、CompletableFuture 等异步编程模型。

从手动管理到框架支持

线程池框架自动管理线程的生命周期,开发者只需提交任务,无需关心线程的创建、复用和销毁。

学习路线建议

学习 JUC 建议按照以下顺序:

  1. 理解并发基础:线程状态、线程安全、内存模型(可见性、有序性、原子性)
  2. 掌握锁机制:从 synchronized 到 ReentrantLock,理解锁的实现原理
  3. 学习线程池:理解线程池参数、任务队列、拒绝策略
  4. 使用并发集合:ConcurrentHashMap、BlockingQueue 等
  5. 应用原子类:CAS 原理、原子类的使用场景
  6. 掌握同步工具:CountDownLatch、CyclicBarrier、Semaphore 等
  7. 进阶内容:Fork/Join 框架、CompletableFuture、虚拟线程(Java 21)

小结

JUC 是 Java 并发编程的核心工具包,它解决了传统并发编程的诸多痛点。通过提供灵活的锁机制、高效的线程池、线程安全的并发集合和无锁原子操作,JUC 让开发者能够更轻松地编写高性能、线程安全的并发程序。

在接下来的章节中,我们将深入探讨 JUC 的各个组件,理解它们的原理和使用方法。