Java 的 java.util.concurrent
(简称 JUC)包是 JDK 5 及以后引入的并发编程工具包,旨在解决传统线程模型(如 synchronized
、wait/notify
)的局限性,提供更灵活、高效、可扩展的并发编程组件。它极大简化了多线程开发,是 Java 并发编程的核心工具。
一、JUC 包的核心作用
传统并发编程依赖 synchronized
关键字和 Object
的 wait()
/notify()
方法,存在灵活性低(锁无法中断、无法超时)、效率有限(重量级锁)等问题。JUC 包通过以下方式改进:
- 提供更细粒度的同步控制(如可中断锁、超时锁);
- 内置线程池管理,避免频繁创建销毁线程的开销;
- 提供线程安全的并发集合(替代
HashMap
等线程不安全的集合); - 封装常用并发工具(如计数器、信号量),减少重复开发。
二、JUC 核心组件分类
JUC 包内容丰富,可分为以下几大模块:
1. 线程池框架(Executor 体系)
线程池是管理线程的容器,避免频繁创建 / 销毁线程的性能损耗,核心接口和类如下:
- Executor:最顶层接口,定义了
execute(Runnable)
方法,用于执行任务。 - ExecutorService:继承
Executor
,增加了线程池生命周期管理(如shutdown()
关闭线程池、submit()
提交带返回值的任务)。 - ThreadPoolExecutor:线程池的核心实现类,需关注 7 个核心参数:
corePoolSize
:核心线程数(始终存活的线程);maximumPoolSize
:最大线程数(核心线程 + 临时线程的上限);keepAliveTime
:临时线程空闲时的存活时间;workQueue
:任务等待队列(核心线程满时,新任务进入队列);threadFactory
:创建线程的工厂;handler
:任务拒绝策略(队列和最大线程都满时的处理方式)。
- Executors:线程池工具类,提供便捷的线程池创建方法(如
newFixedThreadPool
固定大小线程池、newCachedThreadPool
缓存线程池),但实际开发中建议直接使用ThreadPoolExecutor
自定义参数(避免资源耗尽风险)。
2. 并发集合(线程安全的容器)
传统集合(如 HashMap
、ArrayList
)线程不安全,JUC 提供了专门的并发集合,解决多线程读写安全问题:
并发集合类 | 对应传统集合 | 特点与适用场景 |
---|---|---|
ConcurrentHashMap | HashMap | 线程安全的哈希表,JDK 1.8 用 CAS + synchronized 实现(替代分段锁),支持高并发读写。 |
CopyOnWriteArrayList | ArrayList | 读写分离,写操作时复制底层数组,适合读多写少场景(如配置缓存)。 |
CopyOnWriteArraySet | HashSet | 基于 CopyOnWriteArrayList 实现,原理同上。 |
ConcurrentLinkedQueue | LinkedList (队列) | 无锁并发队列,基于 CAS 实现,适合高并发场景的队列操作。 |
BlockingQueue | - | 阻塞队列,提供 put() (满时阻塞)和 take() (空时阻塞)方法,常用于生产者 - 消费者模型。实现类有 ArrayBlockingQueue 、LinkedBlockingQueue 等。 |
3. 同步工具类(控制线程协作)
用于协调多个线程的执行顺序或资源访问,核心工具包括:
Lock 与 Condition:替代
synchronized
和wait()/notify()
的更灵活同步方式。Lock
接口:定义lock()
(获取锁)、tryLock(long, TimeUnit)
(超时获取锁)、unlock()
(释放锁)等方法,实现类ReentrantLock
(可重入锁)是最常用的。Condition
:通过Lock.newCondition()
创建,提供await()
(等待)、signal()
(唤醒单个)、signalAll()
(唤醒所有),可实现多个条件队列(比Object
的单一等待队列更灵活)。
Semaphore(信号量):控制同时访问资源的线程数,类似 “许可证” 机制。例如:
Semaphore semaphore = new Semaphore(3); // 允许3个线程同时访问 semaphore.acquire(); // 获取许可证(若满则阻塞) // 访问资源... semaphore.release(); // 释放许可证
CountDownLatch(倒计时器):等待多个线程完成后再执行主线程。例如:
CountDownLatch latch = new CountDownLatch(5); // 计数5 // 子线程执行完后调用 latch.countDown();(计数-1) latch.await(); // 主线程阻塞,直到计数为0
CyclicBarrier(循环屏障):让多个线程到达 “屏障” 后等待,全部到达后一起继续执行(可重复使用)。例如:
CyclicBarrier barrier = new CyclicBarrier(3, () -> System.out.println("所有线程就绪,开始执行")); // 每个线程执行到 barrier.await() 时等待,直到3个线程都到达
4. 原子类(Atomic 系列)
基于 CAS(Compare-And-Swap,比较并交换)操作,提供线程安全的原子性变量更新,避免使用 synchronized
的开销。核心类:
- 基本类型:
AtomicInteger
、AtomicLong
、AtomicBoolean
(提供getAndIncrement()
原子自增等方法)。 - 引用类型:
AtomicReference
(原子更新对象引用)、AtomicStampedReference
(解决 CAS 的 ABA 问题,带版本号)。 - 数组类型:
AtomicIntegerArray
(原子更新数组元素)。
示例:
AtomicInteger count = new AtomicInteger(0);
count.incrementAndGet(); // 原子自增(替代 count++,线程安全)
5. 其他重要组件
- Future 与 Callable:
Callable
是带返回值的任务(类似Runnable
但有返回值),Future
用于获取Callable
的执行结果。FutureTask
是Future
的实现类,可包装Callable
并作为任务提交给线程池。 - AQS(AbstractQueuedSynchronizer):JUC 许多组件的底层基础(如
ReentrantLock
、Semaphore
),通过维护一个 “同步状态” 和 “双向阻塞队列” 实现同步控制,核心是acquire()
(获取资源)和release()
(释放资源)。
三、JUC 的核心优势
- 更高的灵活性:如
Lock
支持超时、中断,Condition
支持多条件等待。 - 更好的性能:如
ConcurrentHashMap
比Hashtable
效率更高,原子类基于 CAS 避免锁开销。 - 更丰富的功能:内置线程池、阻塞队列、信号量等工具,简化并发编程。
总结
JUC 包是 Java 并发编程的 “瑞士军刀”,涵盖了线程管理、同步控制、并发容器等核心能力。掌握 JUC 组件的原理和适用场景,能有效解决多线程开发中的安全性、性能和可维护性问题,是中高级 Java 开发者的必备知识。