不必逐个背 JUC 源码。先把原子更新、等待完成、控制并发、传递任务、组合结果对应到工具。
原子类与 LongAdder
AtomicInteger 提供 incrementAndGet、compareAndSet 等原子操作,适合精确更新单个数值。多个独立原子操作不会自动组成事务。
LongAdder 在高争用时分散更新,减少单点竞争,适合统计指标。但并发期间 sum 不是统一锁定所有更新的原子快照,不能随意替代限额扣减和状态判断。
常见同步器
| 工具 | 用途 | 边界 |
|---|---|---|
| CountDownLatch | 等待若干任务或步骤完成 | 计数到 0 后放行,不能重置同一个计数 |
| CyclicBarrier | 多个参与方等待到达阶段点 | 可重复使用,需处理超时和屏障破坏 |
| Semaphore | 限制同时访问资源的数量 | 获取后要正确释放,限制并发数而非每秒请求数 |
任务通常在 finally 中 countDown,避免异常路径遗漏计数。但计数归零不意味着全部成功,还要检查任务结果并设定等待超时。
BlockingQueue
put 在容量不足时等待,take 在无元素时等待;offer/poll 支持立即返回或超时。ArrayBlockingQueue 使用固定容量;LinkedBlockingQueue 可指定容量,默认容量很大。
有界队列限制积压,连接生产者和消费者。但队列线程安全不保证业务处理成功,还要处理失败、关闭和重复任务。
Future 与 CompletableFuture
Future 表示异步结果,get 可以阻塞等待,带超时形式限制等待;cancel(true) 尝试中断取消,不保证任务实际已停止。
CompletableFuture 支持组合异步步骤:
CompletableFuture<String> result = CompletableFuture .supplyAsync(() -> loadName(), executor) .thenApply(String::trim) .exceptionally(error -> "unknown");示例指定线程池,转换加载结果并提供降级值;业务是否允许降级要另行决定,不能吞掉所有失败。
- thenApply 转换结果;thenCompose 用于回调返回另一个 Future,避免嵌套。
- thenCombine 合并两个结果;allOf 等一组任务完成,不直接返回结果列表。
- 非 Async 阶段可能由完成任务或其他参与线程执行;Async 版本可指定执行器。
- 常用异步操作未指定执行器时通常使用公共 ForkJoinPool,不适合无边界放入大量阻塞调用。
get 通常通过 ExecutionException 包装失败,join 通常通过 CompletionException 暴露失败。等待超时不等于底层网络调用已取消,还要配置调用本身的超时。
面试回答模板
原子类处理单值更新,LongAdder 适合统计。CountDownLatch 等待完成,CyclicBarrier 同步阶段,Semaphore 控制并发许可。BlockingQueue 连接生产者和消费者。Future 获取异步结果,CompletableFuture 进一步组合步骤;都要考虑线程池、超时、失败和取消。
自测
- Semaphore(10) 是每秒最多 10 次吗?不是。
- allOf 直接返回全部结果列表吗?不返回,需要从各任务获取。
- Future.get 超时后任务一定停止吗?不一定。