开篇概览:JUC 的核心价值与学习路径
JUC(java.util.concurrent) 是 Java 并发编程的高级武器库,由并发大师 Doug Lea 设计,旨在解决传统 synchronized 和 wait/notify 机制的局限性:
- 性能瓶颈:重量级锁开销大;
- 功能单一:缺乏灵活的线程协调机制;
- 易错性高:死锁、活锁、虚假唤醒等问题频发。
JUC 的核心思想是:通过显式锁、原子变量、高级同步器和线程池框架,提供更细粒度的控制、更高的吞吐量和更强大的功能。
本章将严格遵循 “从基础到高级” 的学习路径,系统讲解 JUC 的四大阶段:
- 基石与核心概念(原子变量、显式锁);
- 线程管理与执行框架(线程池、Future);
- 高级同步器与并发数据结构(并发集合、同步器);
- 高级主题与性能优化(Fork/Join、CompletableFuture、底层原理)。
📌 学习前提:
- 已掌握基础多线程知识(
Thread、Runnable、synchronized);- 理解 Java 内存模型(JMM) 与 Happens-Before 原则。
第一阶段:JUC 基石与核心概念
1. JUC 概述与 Happens-Before 原则
1.1 Happens-Before 原则(JMM 核心)
Happens-Before 定义了操作间的可见性与有序性规则,确保多线程程序的正确性。关键规则包括:
- 程序顺序规则:单线程内,前操作 Happens-Before 后操作;
- 监视器锁规则:解锁操作 Happens-Before 后续加锁操作;
- volatile 变量规则:对 volatile 变量的写操作 Happens-Before 后续读操作;
- 线程启动/终止规则:
start()Happens-Before 线程内任何操作;线程内操作 Happens-Beforejoin()返回。
✅ 意义:所有 JUC 组件(如
volatile、synchronized、Lock)都基于此原则保证线程安全。
2. 原子变量类(Atomic Variables)
2.1 核心原理:CAS(Compare-And-Swap)
- 硬件级原子指令:
CAS(value, expected, new); - 无锁编程:避免线程阻塞,提升并发性能;
- ABA 问题:值从 A→B→A,CAS 误判为未修改(可用
AtomicStampedReference解决)。
2.2 示例:AtomicInteger 与 ABA 问题
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicStampedReference;
public class AtomicDemo {
public static void main(String[] args) throws InterruptedException {
// 1. AtomicInteger:无锁计数器
AtomicInteger counter = new AtomicInteger(0);
Thread[] threads = new Thread[10];
for (int i = 0; i < 10; i++) {
threads[i] = new Thread(() -> {
for (int j = 0; j < 1000; j++) {
counter.incrementAndGet(); // 原子自增
}
});
threads[i].start();
}
for (Thread t : threads) t.join();
System.out.println("AtomicInteger 结果: " + counter.get()); // 10000
// 2. AtomicStampedReference:解决 ABA 问题
AtomicStampedReference<String> ref = new AtomicStampedReference<>("A", 0);
// 线程1:尝试将 A→B
new Thread(() -> {
int stamp = ref.getStamp();
System.out.println("线程1 获取版本: " + stamp);
try { Thread.sleep(100); } catch (InterruptedException e) {}
boolean success = ref.compareAndSet("A", "B", stamp, stamp + 1);
System.out.println("线程1 CAS 结果: " + success); // true
}).start();
// 线程2:模拟 ABA(A→C→A)
new Thread(() -> {
int stamp1 = ref.getStamp();
ref.compareAndSet("A", "C", stamp1, stamp1 + 1);
int stamp2 = ref.getStamp();
ref.compareAndSet("C", "A", stamp2, stamp2 + 1);
System.out.println("线程2 完成 ABA,当前版本: " + ref.getStamp());
}).start();
Thread.sleep(200);
}
}
✅ 关键点:
AtomicInteger适用于简单计数场景;AtomicStampedReference通过版本号解决 ABA 问题。
3. 显式锁(Explicit Locks)
3.1 ReentrantLock(可重入锁)
- 优势:可中断、超时、公平锁;
- 必须手动释放:在
finally块中调用unlock()。
3.2 示例:ReentrantLock 高级特性
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.TimeUnit;
public class ReentrantLockDemo {
private final ReentrantLock lock = new ReentrantLock(true); // 公平锁
private int count = 0;
public void increment() {
lock.lock(); // 获取锁
try {
count++;
} finally {
lock.unlock(); // 必须释放
}
}
// 可中断的锁获取
public void tryInterruptibly() throws InterruptedException {
lock.lockInterruptibly(); // 可被 interrupt() 中断
try {
System.out.println("执行可中断任务");
} finally {
lock.unlock();
}
}
// 尝试非阻塞获取锁
public boolean tryLockWithTimeout() {
try {
if (lock.tryLock(1, TimeUnit.SECONDS)) { // 尝试等待1秒
try {
System.out.println("成功获取锁");
return true;
} finally {
lock.unlock();
}
} else {
System.out.println("获取锁超时");
return false;
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return false;
}
}
public static void main(String[] args) throws InterruptedException {
ReentrantLockDemo demo = new ReentrantLockDemo();
// 测试可中断锁
Thread t1 = new Thread(() -> {
try {
demo.tryInterruptibly();
} catch (InterruptedException e) {
System.out.println("线程被中断");
}
});
t1.start();
t1.interrupt(); // 中断线程
// 测试超时锁
demo.tryLockWithTimeout();
}
}
3.3 ReadWriteLock(读写锁)
- 读写分离:允许多个读线程并发,写线程独占;
- 适用场景:读多写少(如缓存)。
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class ReadWriteLockDemo {
private final ReadWriteLock lock = new ReentrantReadWriteLock();
private String data = "初始数据";
// 读操作(共享锁)
public String read() {
lock.readLock().lock();
try {
return data;
} finally {
lock.readLock().unlock();
}
}
// 写操作(独占锁)
public void write(String newData) {
lock.writeLock().lock();
try {
data = newData;
System.out.println("数据已更新: " + newData);
} finally {
lock.writeLock().unlock();
}
}
public static void main(String[] args) {
ReadWriteLockDemo demo = new ReadWriteLockDemo();
// 多个读线程并发执行
for (int i = 0; i < 3; i++) {
new Thread(() -> {
System.out.println("读取: " + demo.read());
}).start();
}
// 写线程
new Thread(() -> demo.write("新数据")).start();
}
}
第二阶段:线程管理与执行框架
4. 线程池(ThreadPoolExecutor)
4.1 核心参数详解
| 参数 | 说明 |
|---|---|
corePoolSize | 核心线程数(即使空闲也不回收) |
maximumPoolSize | 最大线程数 |
keepAliveTime | 非核心线程空闲存活时间 |
workQueue | 任务队列(ArrayBlockingQueue, LinkedBlockingQueue) |
threadFactory | 线程工厂(自定义线程名) |
handler | 拒绝策略(AbortPolicy, CallerRunsPolicy 等) |
4.2 示例:自定义线程池
import java.util.concurrent.*;
public class ThreadPoolDemo {
public static void main(String[] args) {
// 手动创建 ThreadPoolExecutor(避免 Executors 的陷阱)
ThreadPoolExecutor executor = new ThreadPoolExecutor(
2, // corePoolSize
4, // maximumPoolSize
10, // keepAliveTime (秒)
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(2), // 有界队列
new ThreadFactory() { // 自定义线程名
private int count = 1;
@Override
public Thread newThread(Runnable r) {
return new Thread(r, "MyPool-Thread-" + count++);
}
},
new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略:由调用者线程执行
);
// 提交6个任务(2核心 + 2队列 + 2最大 = 6)
for (int i = 1; i <= 6; i++) {
final int taskId = i;
executor.submit(() -> {
System.out.println("任务 " + taskId + " 由 " +
Thread.currentThread().getName() + " 执行");
try { Thread.sleep(1000); } catch (InterruptedException e) {}
});
}
// 关闭线程池
executor.shutdown();
try {
if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
executor.shutdownNow();
}
} catch (InterruptedException e) {
executor.shutdownNow();
}
}
}
✅ 拒绝策略:
AbortPolicy:抛出RejectedExecutionException(默认);CallerRunsPolicy:由提交任务的线程执行;DiscardPolicy:静默丢弃;DiscardOldestPolicy:丢弃队列最旧任务。
5. Future 与 Callable
5.1 Callable vs Runnable
| 特性 | Runnable | Callable |
|---|---|---|
| 返回值 | 无 | 有(V call()) |
| 异常 | 不能抛出受检异常 | 可抛出异常 |
5.2 示例:异步任务与结果获取
import java.util.concurrent.*;
public class FutureDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService executor = Executors.newSingleThreadExecutor();
// 提交 Callable 任务
Callable<Integer> task = () -> {
System.out.println("开始计算...");
Thread.sleep(2000);
return 42;
};
Future<Integer> future = executor.submit(task);
// 异步检查任务状态
while (!future.isDone()) {
System.out.println("任务仍在执行...");
Thread.sleep(500);
}
// 获取结果(阻塞)
Integer result = future.get();
System.out.println("计算结果: " + result); // 42
executor.shutdown();
}
}
第三阶段:高级同步器与并发数据结构
6. 并发集合
6.1 ConcurrentHashMap(高并发 HashMap)
- JDK 8+:采用 CAS + synchronized 替代分段锁;
- 高吞吐量:读操作无锁,写操作锁单个桶。
import java.util.concurrent.ConcurrentHashMap;
public class ConcurrentHashMapDemo {
public static void main(String[] args) throws InterruptedException {
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
// 多线程安全写入
Thread[] threads = new Thread[10];
for (int i = 0; i < 10; i++) {
final int index = i;
threads[i] = new Thread(() -> {
for (int j = 0; j < 100; j++) {
map.compute("key" + index, (k, v) -> (v == null) ? 1 : v + 1);
}
});
threads[i].start();
}
for (Thread t : threads) t.join();
System.out.println("ConcurrentHashMap 大小: " + map.size()); // 10
}
}
6.2 阻塞队列(BlockingQueue)
- 生产者-消费者模式 的标准实现;
- 自动阻塞:队列满时
put()阻塞,空时take()阻塞。
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
public class BlockingQueueDemo {
public static void main(String[] args) {
BlockingQueue<String> queue = new ArrayBlockingQueue<>(2);
// 生产者
new Thread(() -> {
try {
for (int i = 1; i <= 5; i++) {
queue.put("Item-" + i); // 队列满时阻塞
System.out.println("生产: Item-" + i);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}).start();
// 消费者
new Thread(() -> {
try {
while (true) {
String item = queue.take(); // 队列空时阻塞
System.out.println("消费: " + item);
Thread.sleep(1000);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}).start();
}
}
7. 同步器(Synchronizers)
7.1 CountDownLatch(倒计时门闩)
- 一次性:计数归零后无法重置;
- 典型场景:主线程等待多个子线程完成。
import java.util.concurrent.CountDownLatch;
public class CountDownLatchDemo {
public static void main(String[] args) throws InterruptedException {
CountDownLatch latch = new CountDownLatch(3);
for (int i = 0; i < 3; i++) {
new Thread(() -> {
System.out.println("服务启动中...");
try { Thread.sleep(1000); } catch (InterruptedException e) {}
latch.countDown(); // 计数减1
}).start();
}
latch.await(); // 等待计数归零
System.out.println("所有服务已启动,开始处理请求");
}
}
7.2 CyclicBarrier(循环栅栏)
- 可重用:到达屏障点后重置计数;
- 典型场景:多线程分阶段计算。
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class CyclicBarrierDemo {
public static void main(String[] args) {
// 栅栏动作:所有线程到达后执行
CyclicBarrier barrier = new CyclicBarrier(3, () -> {
System.out.println("=== 阶段完成,开始下一阶段 ===");
});
for (int i = 0; i < 3; i++) {
new Thread(() -> {
try {
System.out.println("线程 " + Thread.currentThread().getName() + " 阶段1");
barrier.await(); // 等待其他线程
System.out.println("线程 " + Thread.currentThread().getName() + " 阶段2");
barrier.await();
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
}).start();
}
}
}
7.3 Semaphore(信号量)
- 控制并发数:类似“许可证”机制;
- 典型场景:数据库连接池、限流。
import java.util.concurrent.Semaphore;
public class SemaphoreDemo {
// 模拟只有2个数据库连接
private static final Semaphore semaphore = new Semaphore(2);
public static void accessDatabase(String threadName) {
try {
semaphore.acquire(); // 获取许可证
System.out.println(threadName + " 获取数据库连接");
Thread.sleep(2000); // 模拟数据库操作
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
semaphore.release(); // 释放许可证
System.out.println(threadName + " 释放数据库连接");
}
}
public static void main(String[] args) {
for (int i = 1; i <= 5; i++) {
final String name = "线程-" + i;
new Thread(() -> accessDatabase(name)).start();
}
}
}
第四阶段:高级主题与性能优化
8. Fork/Join 框架
8.1 核心思想:分而治之 + 工作窃取
- Fork:任务拆分;
- Join:结果合并;
- 工作窃取:空闲线程从其他队列“窃取”任务。
8.2 示例:并行计算数组和
import java.util.concurrent.RecursiveTask;
import java.util.concurrent.ForkJoinPool;
public class ForkJoinDemo extends RecursiveTask<Long> {
private final long[] array;
private final int start;
private final int end;
private static final int THRESHOLD = 1000; // 拆分阈值
public ForkJoinDemo(long[] array, int start, int end) {
this.array = array;
this.start = start;
this.end = end;
}
@Override
protected Long compute() {
if (end - start <= THRESHOLD) {
// 小任务直接计算
long sum = 0;
for (int i = start; i < end; i++) {
sum += array[i];
}
return sum;
} else {
// 大任务拆分
int mid = (start + end) / 2;
ForkJoinDemo leftTask = new ForkJoinDemo(array, start, mid);
ForkJoinDemo rightTask = new ForkJoinDemo(array, mid, end);
leftTask.fork(); // 异步执行左任务
Long rightResult = rightTask.compute(); // 同步执行右任务
Long leftResult = leftTask.join(); // 等待左任务结果
return leftResult + rightResult;
}
}
public static void main(String[] args) {
long[] array = new long[10_000_000];
for (int i = 0; i < array.length; i++) {
array[i] = i;
}
ForkJoinPool pool = new ForkJoinPool();
ForkJoinDemo task = new ForkJoinDemo(array, 0, array.length);
long sum = pool.invoke(task);
System.out.println("数组总和: " + sum);
pool.shutdown();
}
}
9. CompletableFuture(Java 8+)
9.1 核心优势:异步流水线
- 非阻塞:避免
Future.get()的阻塞; - 链式调用:组合多个异步任务;
- 异常处理:
exceptionally()统一处理。
9.2 示例:异步任务组合
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
public class CompletableFutureDemo {
public static void main(String[] args) throws InterruptedException {
// 1. 异步执行任务
CompletableFuture<String> future1 = CompletableFuture
.supplyAsync(() -> {
sleep(1);
return "Hello";
});
CompletableFuture<String> future2 = CompletableFuture
.supplyAsync(() -> {
sleep(2);
return "World";
});
// 2. 组合两个任务的结果
CompletableFuture<String> combined = future1
.thenCombine(future2, (s1, s2) -> s1 + " " + s2)
.thenApply(String::toUpperCase);
// 3. 处理结果
combined.thenAccept(System.out::println) // HELLO WORLD
.join(); // 等待完成
// 4. 异常处理
CompletableFuture<String> errorFuture = CompletableFuture
.supplyAsync(() -> {
throw new RuntimeException("模拟异常");
})
.exceptionally(ex -> "默认值");
System.out.println("异常处理结果: " + errorFuture.join()); // 默认值
}
private static void sleep(int seconds) {
try {
TimeUnit.SECONDS.sleep(seconds);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
10. 底层原理:AQS(AbstractQueuedSynchronizer)
10.1 AQS 核心设计
- state:同步状态(如锁计数、信号量许可数);
- CLH 队列:FIFO 等待队列(线程节点组成);
- 模板方法:子类实现
tryAcquire()/tryRelease()定义同步逻辑。
10.2 AQS 在 JUC 中的应用
| 组件 | AQS state 含义 |
|---|---|
ReentrantLock | 锁的持有次数 |
CountDownLatch | 计数器值 |
Semaphore | 剩余许可数 |
ReentrantReadWriteLock | 高16位读锁计数,低16位写锁计数 |
✅ 学习建议:
- 从
ReentrantLock源码入手,理解NonfairSync/FairSync;- 阅读
CountDownLatch的Sync内部类,掌握state变化逻辑。
总结:JUC 学习全景图
| 阶段 | 核心组件 | 典型应用场景 |
|---|---|---|
| 基石 | Atomic*, ReentrantLock, ReadWriteLock | 无锁计数、灵活锁控制 |
| 线程管理 | ThreadPoolExecutor, Future | 任务调度、异步结果 |
| 高级同步 | ConcurrentHashMap, BlockingQueue, CountDownLatch | 高并发集合、生产者-消费者、线程协调 |
| 高级优化 | ForkJoinPool, CompletableFuture, AQS | 并行计算、异步流水线、底层原理 |
📌 终极建议:
“先会用,再懂理;先模仿,再创新。”
从AtomicInteger和ThreadPoolExecutor开始实践,逐步挑战AQS源码。掌握 JUC,你将具备设计高并发、高可用系统的硬核能力。
1072

被折叠的 条评论
为什么被折叠?



