JUC 工具类
约 875 字大约 3 分钟
布欧-Lewyon
2026-05-16
java.util.concurrent(JUC)提供了比底层 synchronized/volatile 更高级的工具:显式锁、并发容器、原子变量以及异步编排工具。
Lock 接口
Lock 提供了比 synchronized 更灵活的操作:可中断、可超时、可尝试获取锁。
ReentrantLock
Lock lock = new ReentrantLock();
lock.lock();
try {
// 临界区
} finally {
lock.unlock(); // 务必在 finally 中释放
}与 synchronized 的区别:
| 特性 | synchronized | ReentrantLock |
|---|---|---|
| 自动释放 | ✅ 退出代码块自动释放 | ❌ 必须手动 unlock() |
| 可中断 | ❌ | ✅ lockInterruptibly() |
| 超时尝试 | ❌ | ✅ tryLock(1, TimeUnit.SECONDS) |
| 公平锁 | ❌ 非公平 | ✅ 构造器传入 true 开启 |
| 条件变量 | wait()/notify() | Condition.await()/signal() |
ReadWriteLock
读写分离锁:读读不互斥,读写/写写互斥,适合读多写少的场景:
ReadWriteLock rwLock = new ReentrantReadWriteLock();
// 读取
rwLock.readLock().lock();
try {
// 多个线程可同时进入
} finally {
rwLock.readLock().unlock();
}
// 写入
rwLock.writeLock().lock();
try {
// 排他
} finally {
rwLock.writeLock().unlock();
}ConcurrentHashMap
ConcurrentHashMap 是线程安全的 HashMap,在 Java 8+ 中使用桶粒度 CAS + synchronized,性能远优于用 synchronizedMap 或 Hashtable:
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
// 原子操作
map.putIfAbsent("key", 1); // 不存在才放入
map.computeIfAbsent("key", k -> computeExpensiveValue(k)); // 不存在则计算后放入
map.merge("key", 1, Integer::sum); // 原子累加- 迭代器不抛
ConcurrentModificationException(弱一致性)。 size()返回近似值,不是精确值。- 不要用
HashMap+synchronized替代——ConcurrentHashMap在几乎所有场景都更快。
原子类(Atomic*)
AtomicInteger、AtomicLong、AtomicReference 等通过 CAS(Compare-And-Swap)实现无锁的原子操作,比 synchronized 更轻量:
AtomicInteger counter = new AtomicInteger(0);
// 原子操作
counter.incrementAndGet(); // ++i
counter.getAndIncrement(); // i++
counter.addAndGet(5); // += 5
counter.compareAndSet(10, 20); // 期望值为 10 则更新为 20适用场景:计数器、序列生成器、统计指标等简单数值操作。复合操作仍需 synchronized 或 Lock。
CompletableFuture
CompletableFuture(Java 8+)比 Future 强大得多:支持异步回调、任务编排和异常处理。
基本用法
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
// 在 ForkJoinPool.commonPool() 中异步执行
return "Hello";
});
// 结果回调
future.thenAccept(result -> System.out.println(result));
// 阻塞获取(不推荐在主流程中用)
String result = future.get();任务编排
CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> 10);
CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> 20);
// 两个都完成后合并
CompletableFuture<Integer> combined = future1
.thenCombine(future2, (a, b) -> a + b);
// 任一完成即返回
CompletableFuture<Object> any = CompletableFuture.anyOf(future1, future2);
// 全部完成后执行
CompletableFuture<Void> all = CompletableFuture.allOf(future1, future2);异常处理
CompletableFuture.supplyAsync(() -> {
if (Math.random() > 0.5) throw new RuntimeException("出错了");
return 42;
}).exceptionally(ex -> {
System.err.println("错误: " + ex.getMessage());
return 0; // 返回默认值
}).thenAccept(result -> System.out.println("结果: " + result));自定义线程池
默认使用 ForkJoinPool.commonPool();批量 IO 操作时建议传入自定义线程池:
ExecutorService executor = Executors.newFixedThreadPool(10);
CompletableFuture.supplyAsync(() -> fetchData(), executor);小结
ReentrantLock比synchronized灵活(可中断、超时、公平),但必须手动释放。ReadWriteLock适合读多写少场景,读写锁分离提高并发度。ConcurrentHashMap是线程安全的 HashMap 首选,比Hashtable和synchronizedMap性能更好。AtomicInteger等原子类通过 CAS 实现无锁原子操作,适合计数器场景。CompletableFuture支持异步编排(thenCombine/allOf/exceptionally),现代 Java 异步编程的核心工具。- 易错:
CompletableFuture默认使用ForkJoinPool.commonPool(),这是一个所有并行流和 CompletableFuture 共享的线程池;阻塞操作(如数据库查询)会耗尽池中线程,应传入自定义线程池。 - 思考任务:使用
CompletableFuture+ 自定义线程池实现:同时查询两个远程 API,合并结果后返回;处理其中一个失败的情况,给出默认值。
上一节:同步与可见性
下一节:虚拟线程
