一、为什么引入JUC
Java 并发工具包(java.util.concurrent
,简称 JUC )的引入是为了解决多线程编程中的复杂性、性能瓶颈和安全性问题 。在原生 Java 线程模型(Thread
、synchronized
、wait/notify
)基础上,JUC 提供了更高效、更灵活的工具,核心解决以下关键问题:
1. 原生同步机制的局限性
synchronized
性能问题 :
原生synchronized
是重量级锁,在竞争激烈时会导致线程频繁挂起/唤醒,引发上下文切换开销。JUC 提供了可重入锁(ReentrantLock
) ,支持:- 非阻塞尝试获取锁(
tryLock()
) - 可中断锁(
lockInterruptibly()
) - 公平锁选项(减少线程饥饿)
- 更细粒度的锁控制(配合
Condition
实现多条件等待)。
- 非阻塞尝试获取锁(
wait/notify
难以维护 :
在多条件等待场景中(如生产者-消费者),wait/notify
易引发错误(如虚假唤醒)。JUC 的Condition
接口 支持多条件队列,简化复杂同步逻辑。
2. 线程安全容器的性能瓶颈
Collections.synchronizedXXX
效率低 :
通过同步包装的集合(如synchronizedList
)使用粗粒度锁,所有操作串行化。JUC 提供了高性能并发容器 :ConcurrentHashMap
:分段锁/无锁 CAS 实现高并发读/写。CopyOnWriteArrayList
:读无锁,写时复制(适合读多写少)。BlockingQueue
(如ArrayBlockingQueue
,LinkedBlockingQueue
):线程安全的阻塞队列,简化生产者-消费者模型。
3. 复杂并发任务的协作困难
原生线程 API 难以协调多线程任务,JUC 提供以下工具:
CountDownLatch
:
让主线程等待多个子任务完成(如启动初始化)。CyclicBarrier
:
让一组线程相互等待,直到所有线程到达屏障点(如多阶段计算)。Semaphore
:
控制同时访问资源的线程数(如限流)。Phaser
:
更灵活的分阶段屏障(替代CountDownLatch
和CyclicBarrier
)。
4. 线程池管理的复杂性
- 原生
Thread
开销大 :
频繁创建/销毁线程消耗资源。JUC 提供Executor
框架 :- 线程池(
ThreadPoolExecutor
,ScheduledThreadPoolExecutor
)复用线程资源。 - 支持任务提交(
submit()
)、生命周期管理、拒绝策略等。 - 避免手动管理线程。
- 线程池(
5. 原子操作的实现成本
volatile
不够灵活 :
volatile
只保证可见性,不保证复合操作原子性。JUC 的atomic
包 (如AtomicInteger
,AtomicReference
)通过 CAS(无锁算法) 实现高效原子操作,避免锁开销。
6. 避免死锁和提高可扩展性
- 锁分离与无锁算法 :
如ConcurrentHashMap
分段锁减少竞争,CopyOnWriteArrayList
读操作无锁,提升高并发场景性能。 - 非阻塞数据结构 :
例如ConcurrentLinkedQueue
使用 CAS 实现无锁队列,避免死锁。
代码示例对比
原生 synchronized
vs ReentrantLock
java
// 原生 synchronized
synchronized(lock) {
while (!condition) lock.wait();
// 操作资源
lock.notifyAll();
}
// JUC ReentrantLock + Condition
lock.lock();
try {
while (!condition) condition.await();
// 操作资源
condition.signal();
} finally {
lock.unlock();
}
ReentrantLock
支持超时、中断,且 Condition
可细分等待条件(如生产者/消费者独立队列)。
二、JUC 工具包核心组件
1. Lock 框架 (java.util.concurrent.locks)
Lock ReentrantLock AbstractQueuedSynchronizer Sync NonfairSync FairSync Condition
-
ReentrantLock
javaLock lock = new ReentrantLock(true); // 公平锁 lock.lockInterruptibly(); // 可中断获取锁 try { // 临界区 } finally { lock.unlock(); }
-
ReadWriteLock
javaReentrantReadWriteLock rwLock = new ReentrantReadWriteLock(); rwLock.readLock().lock(); // 读锁共享 rwLock.writeLock().lock(); // 写锁排他
-
Condition
javaCondition condition = lock.newCondition(); condition.await(1, TimeUnit.SECONDS); // 超时等待 condition.signal(); // 唤醒线程
2. 原子类 (java.util.concurrent.atomic)
-
实现原理 :CAS (Unsafe.compareAndSwapXXX)
c++// HotSpot 源码片段 (atomic.cpp) jbyte Atomic::cmpxchg(jbyte exchange_value, volatile jbyte* dest...) { return __sync_val_compare_and_swap(dest, compare_value, exchange_value); }
-
示例
javaAtomicInteger atomicInt = new AtomicInteger(); atomicInt.updateAndGet(x -> x * 2); // 原子更新 // LongAdder 分段计数优化高并发 LongAdder adder = new LongAdder(); adder.add(10);
3. 并发容器
容器类 | 特性 | 实现原理 |
---|---|---|
ConcurrentHashMap |
分段锁/CAS+synchronized | JDK8: Node数组+链表/红黑树 |
CopyOnWriteArrayList |
写时复制 | 写操作加锁复制新数组 |
ConcurrentLinkedQueue |
无锁队列 | CAS更新头尾节点 |
BlockingQueue |
阻塞操作 | Condition等待队列 |
java
// ConcurrentHashMap 使用示例
ConcurrentMap<String, Integer> map = new ConcurrentHashMap<>();
map.computeIfAbsent("key", k -> 1); // 原子操作
4. 同步工具类
-
CountDownLatch:一次性屏障
javaCountDownLatch latch = new CountDownLatch(3); latch.await(); // 主线程等待 latch.countDown(); // 任务线程完成
-
CyclicBarrier:可重用栅栏
javaCyclicBarrier barrier = new CyclicBarrier(5, () -> System.out.println("All threads arrived")); barrier.await(); // 线程同步点
-
Semaphore:资源许可证
javaSemaphore sem = new Semaphore(5); // 资源池容量 sem.acquire(); // 获取许可 sem.release(); // 释放许可
-
Exchanger:线程间数据交换
javaExchanger<String> exchanger = new Exchanger<>(); String data = exchanger.exchange("Data"); // 阻塞等待交换
5. 线程池框架
Executor ExecutorService AbstractExecutorService ThreadPoolExecutor ScheduledExecutorService
-
核心参数
javanew ThreadPoolExecutor( corePoolSize, // 核心线程数 maxPoolSize, // 最大线程数 keepAliveTime, // 空闲线程存活时间 TimeUnit.SECONDS, new LinkedBlockingQueue(100), // 工作队列 new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略 )
-
ForkJoinPool 工作窃取算法
javaclass FibTask extends RecursiveTask<Integer> { protected Integer compute() { if (n <= 1) return n; FibTask f1 = new FibTask(n-1); f1.fork(); // 拆分子任务 return f2.compute() + f1.join(); } }
三、深入源码解析
1. AQS (AbstractQueuedSynchronizer) 机制
java
// ReentrantLock 获取锁源码片段
final boolean nonfairTryAcquire(int acquires) {
if (compareAndSetState(0, 1)) { // CAS尝试设置state
setExclusiveOwnerThread(current);
return true;
}
return false;
}
// 等待队列入队操作 (CLH队列)
private Node enq(Node node) {
for (;;) {
Node t = tail;
if (t == null) // 初始化队列
if (compareAndSetHead(new Node()))
tail = head;
else {
node.prev = t;
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
}
}
2. ConcurrentHashMap 扩容设计
java
// 扩容时数据迁移 (transfer方法)
while (nextTab != null && transferIndex > 0) {
synchronized (f) { // 锁住桶头节点
// 将链表/树拆分成高位和低位链表
if (fh >= 0) {
Node<K,V> loHead = null, loTail = null;
Node<K,V> hiHead = null, hiTail = null;
// ...数据迁移操作...
}
}
}
3. FutureTask 状态机
java
// FutureTask 状态转换
private static final int NEW = 0; // 新建
private static final int COMPLETING = 1; // 执行中
private static final int NORMAL = 2; // 正常结束
private static final int EXCEPTIONAL = 3; // 异常结束
private static final int CANCELLED = 4; // 已取消
private static final int INTERRUPTING = 5; // 中断中
private static final int INTERRUPTED = 6; // 已中断
四、高级特性与最佳实践
-
避免死锁的技巧
- 锁排序:按固定顺序获取锁
- 使用
tryLock()
带超时机制
javaif (lock1.tryLock(1, SECONDS)) { try { if (lock2.tryLock(1, SECONDS)) { try { /* 业务操作 */ } finally { lock2.unlock(); } } } finally { lock1.unlock(); } }
-
JMM(Java Memory Model)原则
- Happens-Before 规则:
- 程序顺序规则
- volatile变量规则
- 传递性规则
- Happens-Before 规则:
-
性能优化
- 用 LongAdder 替代 AtomicLong 高并发计数
- 避免锁升级:优先用 volatile + CAS
- ConcurrentHashMap.size() vs mappingCount()
五、Java 并发发展
- Java 19 虚拟线程(Virtual Threads)
- Java 21 结构化并发
- Project Loom 的协程实现
学习路径建议:
- 掌握基础锁机制 → 2. 熟练使用 JUC 工具类 → 3. 阅读源码理解原理 → 4. 通过 Arthas 等工具实战调试 → 5. 学习性能调优方案
六、总结
JUC 的核心价值:
- 提升性能:通过无锁算法(CAS)、细粒度锁、并发容器减少竞争。
- 简化复杂性 :标准化工具(如线程池、
BlockingQueue
)替代手写复杂同步逻辑。 - 增强安全性:避免死锁、竞争条件,提供更可靠的线程协作机制。
- 可扩展性:支持高并发场景(如百万级连接的服务端)。
理解并发工具包需要结合底层硬件知识(CPU缓存、内存屏障)和操作系统原理(线程调度、同步原语),通过工具包源码的学习能帮助开发者编写高性能、线程安全的并发程序。