JUC并发包深度解析:原理、示例与实战场景
一、AtomicInteger:原子整数操作
1. 底层原理
核心机制:
-
CAS操作(Compare And Swap):通过CPU原子指令保证操作的原子性
-
自旋重试:当多个线程竞争时,失败的线程会循环重试而非阻塞
-
内存屏障:保证修改后的值对其他线程立即可见(volatile语义)
2. 代码示例(带详细注释)
import java.util.concurrent.atomic.AtomicInteger;
public class AtomicExample {
// 创建原子整数,初始值为0
private static AtomicInteger counter = new AtomicInteger(0);
public static void main(String[] args) throws InterruptedException {
// 创建10个线程
Thread[] threads = new Thread[10];
for (int i = 0; i < 10; i++) {
threads[i] = new Thread(() -> {
for (int j = 0; j < 1000; j++) {
// 原子自增操作(替代i++)
counter.incrementAndGet();
/* 等效于以下操作:
* int current;
* do {
* current = counter.get(); // 读取当前值
* } while (!counter.compareAndSet(current, current + 1)); // CAS更新
*/
}
});
threads[i].start();
}
// 等待所有线程完成
for (Thread t : threads) {
t.join();
}
System.out.println("最终结果: " + counter.get()); // 正确输出10000
}
}
3. 实战场景:分布式ID生成器
**需求背景:**在订单系统中需要生成全局唯一ID,要求高性能、无冲突
解决方案:AtomicInteger + 时间戳组合
public class OrderIdGenerator {
// 原子计数器(每天重置)
private static AtomicInteger dailyCounter = new AtomicInteger(0);
// 最后日期记录(避免跨天问题)
private static volatile String lastDate = "";
public static String generateOrderId() {
String today = LocalDate.now().format(DateTimeFormatter.BASIC_ISO_DATE);
// 日期变更检测(双重检查锁)
if (!today.equals(lastDate)) {
synchronized (OrderIdGenerator.class) {
if (!today.equals(lastDate)) {
dailyCounter.set(0);
lastDate = today;
}
}
}
// 组合ID:日期+原子计数(6位补零)
return today + String.format("%06d", dailyCounter.incrementAndGet());
}
}
// 使用示例
public class OrderService {
public Order createOrder() {
Order order = new Order();
order.setId(OrderIdGenerator.generateOrderId()); // 生成唯一ID
// 其他业务逻辑...
return order;
}
}
二、ReentrantLock:可重入锁
1. 底层原理
核心机制:
-
AQS队列(AbstractQueuedSynchronizer):维护等待线程的CLH队列
-
可重入性:允许线程多次获取同一把锁
-
公平性选择:公平锁(FIFO) vs 非公平锁(插队机制)
2. 代码示例(带详细注释)
import java.util.concurrent.locks.ReentrantLock;
public class LockExample {
// 创建可重入锁(默认非公平)
private static final ReentrantLock lock = new ReentrantLock();
private static int sharedResource = 0;
public static void main(String[] args) {
Runnable task = () -> {
for (int i = 0; i < 1000; i++) {
lock.lock(); // 获取锁(阻塞直到成功)
try {
// 临界区开始
sharedResource++;
// 可重入演示
if (sharedResource % 100 == 0) {
nestedLockDemo();
}
// 临界区结束
} finally {
lock.unlock(); // 必须在finally中释放锁
}
}
};
new Thread(task).start();
new Thread(task).start();
}
private static void nestedLockDemo() {
lock.lock(); // 可重入获取同一把锁
try {
System.out.println("重入层级: " + lock.getHoldCount());
} finally {
lock.unlock();
}
}
}
3. 实战场景:银行账户转账
需求背景:金融系统中需要保证转账操作的原子性,避免死锁
解决方案:ReentrantLock + 超时控制
public class BankAccount {
private final String accountId;
private int balance;
// 账户专属锁(避免锁整个银行系统)
private final ReentrantLock lock = new ReentrantLock();
public BankAccount(String accountId, int balance) {
this.accountId = accountId;
this.balance = balance;
}
// 安全的转账操作
public boolean transferTo(BankAccount target, int amount) {
// 获取当前时间(用于超时计算)
long start = System.currentTimeMillis();
while (true) {
// 尝试获取当前账户锁(带超时)
if (lock.tryLock(300, TimeUnit.MILLISECONDS)) {
try {
// 尝试获取目标账户锁(带超时)
if (target.lock.tryLock(300, TimeUnit.MILLISECONDS)) {
try {
// 双锁保护下的转账操作
if (this.balance >= amount) {
this.balance -= amount;
target.balance += amount;
System.out.printf("%s 向 %s 转账 %d 成功%n",
accountId, target.accountId, amount);
return true;
} else {
System.out.println("余额不足");
return false;
}
} finally {
target.lock.unlock();
}
}
} finally {
lock.unlock();
}
}
// 超时检测
if (System.currentTimeMillis() - start > 1000) {
System.out.println("转账超时,请重试");
return false;
}
// 随机睡眠避免活锁
try {
Thread.sleep(10 + new Random().nextInt(50));
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
}
// 使用示例
public class BankingSystem {
public static void main(String[] args) {
BankAccount alice = new BankAccount("A1001", 5000);
BankAccount bob = new BankAccount("B2002", 3000);
// 并发转账
new Thread(() -> alice.transferTo(bob, 100)).start();
new Thread(() -> bob.transferTo(alice, 200)).start();
}
}
三、BlockingQueue:阻塞队列
1. 底层原理
核心机制:
-
双条件队列:notFull(生产者等待条件)和 notEmpty(消费者等待条件)
-
阻塞/唤醒机制:基于Lock/Condition实现
-
容量策略:有界队列(ArrayBlockingQueue) vs 无界队列(LinkedBlockingQueue)
2. 代码示例(带详细注释)
import java.util.concurrent.*;
public class BlockingQueueExample {
public static void main(String[] args) throws InterruptedException {
// 创建容量为5的阻塞队列
BlockingQueue<String> queue = new ArrayBlockingQueue<>(5);
// 生产者线程
Thread producer = new Thread(() -> {
try {
String[] items = {"A", "B", "C", "D", "E", "F"};
for (String item : items) {
// 如果队列满则阻塞等待
queue.put(item);
System.out.println("生产: " + item);
Thread.sleep(100);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
// 消费者线程
Thread consumer = new Thread(() -> {
try {
while (true) {
// 如果队列空则阻塞等待
String item = queue.take();
System.out.println("消费: " + item);
Thread.sleep(200);
// 队列状态监控
System.out.println("队列状态: " + queue);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
producer.start();
consumer.start();
producer.join();
consumer.join();
}
}
3. 实战场景:电商订单处理系统
需求背景:大促期间订单量激增,需要缓冲订单处理压力
解决方案:多层阻塞队列 + 线程池
public class OrderProcessingSystem {
// 1. 订单接收队列(内存缓冲)
private final BlockingQueue<Order> orderQueue = new LinkedBlockingQueue<>(1000);
// 2. 订单处理线程池
private final ExecutorService processorPool = Executors.newFixedThreadPool(8);
// 3. 失败订单队列(持久化存储)
private final BlockingQueue<Order> failedOrderQueue = new ArrayBlockingQueue<>(100);
public void start() {
// 启动订单接收服务
startOrderReceiver();
// 启动订单处理线程
for (int i = 0; i < 8; i++) {
processorPool.execute(this::processOrders);
}
// 启动失败订单重试线程
new Thread(this::retryFailedOrders).start();
}
private void startOrderReceiver() {
new Thread(() -> {
while (true) {
try {
// 从消息队列获取订单(模拟)
Order order = fetchOrderFromMQ();
// 放入内存队列(阻塞直到有空间)
orderQueue.put(order);
System.out.println("接收订单: " + order.getId());
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
}
}).start();
}
private void processOrders() {
while (!Thread.currentThread().isInterrupted()) {
try {
// 从队列获取订单(阻塞直到有订单)
Order order = orderQueue.take();
try {
// 处理订单(支付、库存扣减等)
processOrder(order);
} catch (Exception e) {
// 处理失败放入重试队列
failedOrderQueue.put(order);
System.err.println("订单处理失败: " + order.getId());
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
private void retryFailedOrders() {
while (!Thread.currentThread().isInterrupted()) {
try {
// 获取失败订单(带超时)
Order order = failedOrderQueue.poll(30, TimeUnit.SECONDS);
if (order != null) {
// 重试逻辑(带指数退避)
retryOrder(order);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
}
四、CountDownLatch:倒计时门闩
1. 底层原理
核心机制:
-
一次性门闩:计数归零后无法重置
-
共享锁模式:基于AQS的共享锁实现
-
无阻塞检查:getCount()方法可随时获取当前计数
2. 代码示例(带详细注释)
import java.util.concurrent.CountDownLatch;
public class CountDownLatchExample {
public static void main(String[] args) throws InterruptedException {
// 创建倒计时门闩(计数=3)
CountDownLatch startSignal = new CountDownLatch(1);
CountDownLatch doneSignal = new CountDownLatch(3);
// 创建3个工作线程
for (int i = 0; i < 3; i++) {
new Thread(new Worker(startSignal, doneSignal, "Worker-" + (i+1))).start();
}
System.out.println("主线程准备阶段...");
Thread.sleep(2000); // 模拟初始化时间
System.out.println("主线程发出启动信号");
startSignal.countDown(); // 释放所有工作线程
doneSignal.await(); // 等待所有工作线程完成
System.out.println("所有工作线程已完成任务");
}
static class Worker implements Runnable {
private final CountDownLatch startSignal;
private final CountDownLatch doneSignal;
private final String name;
Worker(CountDownLatch start, CountDownLatch done, String name) {
this.startSignal = start;
this.doneSignal = done;
this.name = name;
}
public void run() {
try {
System.out.println(name + " 等待启动信号...");
startSignal.await(); // 等待主线程信号
System.out.println(name + " 开始工作");
Thread.sleep(1000 + new Random().nextInt(1000)); // 模拟工作
System.out.println(name + " 工作完成");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
doneSignal.countDown(); // 完成任务计数减1
}
}
}
}
3. 实战场景:微服务启动依赖检查
需求背景:系统包含多个微服务,主服务启动前需验证所有依赖服务可用
解决方案:CountDownLatch + 健康检查
public class ServiceInitializer {
// 依赖服务列表
private static final List<String> DEPENDENCIES = Arrays.asList(
"auth-service",
"payment-service",
"inventory-service"
);
public void initializeSystem() {
// 创建门闩(数量=依赖服务数)
CountDownLatch latch = new CountDownLatch(DEPENDENCIES.size());
// 创建线程池
ExecutorService executor = Executors.newFixedThreadPool(DEPENDENCIES.size());
// 并行检查所有依赖服务
for (String service : DEPENDENCIES) {
executor.execute(() -> {
try {
if (checkServiceHealth(service)) {
System.out.println(service + " 健康检查通过");
} else {
System.err.println(service + " 健康检查失败");
}
} finally {
latch.countDown(); // 无论成功失败都计数减1
}
});
}
try {
// 设置超时时间(5秒)
if (latch.await(5, TimeUnit.SECONDS)) {
System.out.println("所有服务健康检查完成");
startMainService();
} else {
// 获取未完成的服务
long missing = latch.getCount();
System.err.println(missing + " 个服务未完成检查,启动终止");
// 强制关闭线程池
executor.shutdownNow();
System.exit(1);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
executor.shutdown();
}
}
private boolean checkServiceHealth(String serviceName) {
// 模拟健康检查(真实场景调用HTTP/健康端点)
try {
Thread.sleep(500 + new Random().nextInt(1000));
return new Random().nextDouble() > 0.2; // 80%成功率
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return false;
}
}
}
五、CompletableFuture:异步编程利器
1. 底层原理
核心机制:
-
任务编排:通过链式调用组合多个异步任务
-
工作窃取线程池:默认使用ForkJoinPool.commonPool()
-
回调机制:支持thenApply/thenAccept/thenRun等回调方法
-
组合操作:支持thenCompose/thenCombine/allOf/anyOf等组合方法
2. 代码示例(带详细注释)
import java.util.concurrent.*;
public class CompletableFutureExample {
public static void main(String[] args) throws Exception {
// 示例1:基本异步操作
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
System.out.println("异步任务执行中..." + Thread.currentThread().getName());
sleep(1000); // 模拟耗时操作
return "Hello";
});
// 异步结果处理(非阻塞)
future.thenAccept(result -> System.out.println("结果处理: " + result));
// 示例2:任务链式调用
CompletableFuture<String> combined = CompletableFuture.supplyAsync(() -> {
sleep(500);
return "World";
})
.thenApplyAsync(first -> {
System.out.println("第一阶段结果: " + first);
return first + " Java";
})
.thenCombine(future, (second, first) -> first + " " + second);
System.out.println("最终结果: " + combined.get());
// 示例3:异常处理
CompletableFuture<Integer> safeFuture = CompletableFuture.supplyAsync(() -> {
if (Math.random() > 0.5) throw new RuntimeException("模拟异常");
return 42;
}).exceptionally(ex -> {
System.err.println("捕获异常: " + ex.getMessage());
return 0; // 默认值
});
System.out.println("安全结果: " + safeFuture.get());
}
private static void sleep(int millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
3. 实战场景:电商商品详情页聚合
需求背景:商品详情页需聚合商品信息、库存、评价、推荐等6个服务的数据
挑战:服务响应时间差异大(50ms~2s),需要并行调用
解决方案:CompletableFuture多服务并行调用
public class ProductDetailService {
// 并行获取所有服务数据
public ProductDetail loadProductDetail(String productId) {
// 1. 创建各服务的异步任务
CompletableFuture<ProductInfo> infoFuture = CompletableFuture.supplyAsync(
() -> productService.getInfo(productId));
CompletableFuture<Integer> stockFuture = CompletableFuture.supplyAsync(
() -> inventoryService.getStock(productId));
CompletableFuture<List<Review>> reviewsFuture = CompletableFuture.supplyAsync(
() -> reviewService.getReviews(productId));
CompletableFuture<List<Recommendation>> recommendsFuture = CompletableFuture.supplyAsync(
() -> recommendService.getRecommends(productId));
CompletableFuture<PriceInfo> priceFuture = CompletableFuture.supplyAsync(
() -> priceService.getPriceInfo(productId));
CompletableFuture<Promotion> promotionFuture = CompletableFuture.supplyAsync(
() -> promotionService.getPromotion(productId));
// 2. 等待所有任务完成(带超时)
CompletableFuture<Void> allFutures = CompletableFuture.allOf(
infoFuture, stockFuture, reviewsFuture,
recommendsFuture, priceFuture, promotionFuture
);
try {
// 设置总超时时间(800ms)
allFutures.get(800, TimeUnit.MILLISECONDS);
} catch (TimeoutException e) {
// 部分服务超时处理
System.err.println("部分服务响应超时,返回降级数据");
} catch (Exception e) {
throw new RuntimeException("聚合失败", e);
}
// 3. 构建返回结果(即使部分失败也返回可用数据)
return ProductDetail.builder()
.info(getOrNull(infoFuture))
.stock(getOrNull(stockFuture))
.reviews(getOrNull(reviewsFuture))
.recommendations(getOrNull(recommendsFuture))
.priceInfo(getOrNull(priceFuture))
.promotion(getOrNull(promotionFuture))
.build();
}
// 安全获取结果(避免异常传播)
private <T> T getOrNull(CompletableFuture<T> future) {
try {
return future.getNow(null); // 立即获取当前结果
} catch (Exception e) {
return null;
}
}
}
// 使用示例
public class ProductController {
@GetMapping("/product/{id}")
public ProductDetail getDetail(@PathVariable String id) {
return new ProductDetailService().loadProductDetail(id);
}
}
六、Semaphore:资源访问控制器
1. 底层原理
核心机制:
-
资源许可证:每个线程需获取许可证才能访问资源
-
公平性选择:支持公平/非公平两种模式
-
可中断获取:支持带超时的tryAcquire方法
-
信号量回收:释放许可证后可供其他线程使用
2. 代码示例(带详细注释)
import java.util.concurrent.*;
public class SemaphoreExample {
public static void main(String[] args) {
// 创建信号量(3个许可证)
Semaphore semaphore = new Semaphore(3, true); // 公平模式
// 创建10个线程竞争资源
ExecutorService executor = Executors.newFixedThreadPool(10);
for (int i = 0; i < 10; i++) {
executor.execute(new ResourceUser(semaphore, "Worker-" + i));
}
executor.shutdown();
}
static class ResourceUser implements Runnable {
private final Semaphore semaphore;
private final String name;
ResourceUser(Semaphore semaphore, String name) {
this.semaphore = semaphore;
this.name = name;
}
public void run() {
try {
System.out.println(name + " 等待获取资源...");
// 尝试在2秒内获取许可(避免永久阻塞)
if (semaphore.tryAcquire(2, TimeUnit.SECONDS)) {
try {
System.out.println(name + " 获取资源成功! 剩余许可: "
+ semaphore.availablePermits());
// 模拟资源使用
Thread.sleep(1000 + new Random().nextInt(1000));
} finally {
semaphore.release(); // 必须释放
System.out.println(name + " 释放资源");
}
} else {
System.err.println(name + " 获取资源超时!");
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
}
3. 实战场景:API限流系统
需求背景:第三方支付接口限制每秒最大调用次数(100次/秒)
挑战:突发流量可能导致服务被禁用
解决方案:Semaphore + 定时重置
public class RateLimiter {
// 每秒最大请求数
private final int maxPermitsPerSecond;
// 当前可用的许可证
private volatile Semaphore semaphore;
public RateLimiter(int maxPermitsPerSecond) {
this.maxPermitsPerSecond = maxPermitsPerSecond;
this.semaphore = new Semaphore(maxPermitsPerSecond);
startResetTask();
}
// 尝试执行受保护的API调用
public <T> T callWithLimit(Callable<T> task) throws Exception {
if (semaphore.tryAcquire()) {
try {
return task.call(); // 执行受保护的API调用
} finally {
// 不需要手动释放,通过定时器重置
}
} else {
throw new RateLimitExceededException("API调用频率超过限制");
}
}
// 每秒重置信号量
private void startResetTask() {
ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
scheduler.scheduleAtFixedRate(() -> {
int current = semaphore.availablePermits();
int needRelease = maxPermitsPerSecond - current;
if (needRelease > 0) {
semaphore.release(needRelease); // 补充许可证
}
}, 0, 1, TimeUnit.SECONDS); // 每秒触发
}
}
// 使用示例
public class PaymentService {
private final RateLimiter rateLimiter = new RateLimiter(100);
public PaymentResult processPayment(PaymentRequest request) {
try {
return rateLimiter.callWithLimit(() -> {
// 调用第三方支付API
return thirdPartyPaymentAPI.process(request);
});
} catch (RateLimitExceededException e) {
// 触发降级策略
return localFallback(request);
} catch (Exception e) {
throw new PaymentException("支付失败", e);
}
}
}
总结:JUC组件选型指南
场景特征 | 推荐组件 | 原因说明 |
---|---|---|
简单计数器 | AtomicInteger | 轻量无锁,性能高 |
资源互斥访问 | ReentrantLock | 灵活控制,支持条件等待 |
生产者-消费者模式 | BlockingQueue | 天然解耦,自动流量控制 |
多任务等待 | CountDownLatch | 简单可靠,一次性协调 |
循环多阶段任务 | CyclicBarrier | 可重用,支持回调 |
资源池管理 | Semaphore | 精准控制并发数量 |
异步任务链 | CompletableFuture | 函数式编程,链式调用 |
最佳实践原则:
-
优先无锁:能用原子类解决的问题不用锁
-
锁粒度最小化:减小临界区范围
-
超时控制:所有阻塞操作必须设置超时
-
资源清理:finally块中释放锁和资源
-
线程命名:通过线程工厂命名线程,便于诊断
高级应用技巧
1. CompletableFuture组合技巧
// 多结果合并(等待所有任务完成)
CompletableFuture<Void> all = CompletableFuture.allOf(future1, future2, future3);
// 任一完成(返回第一个完成的结果)
CompletableFuture<Object> any = CompletableFuture.anyOf(future1, future2);
// 结果转换链
CompletableFuture<String> pipeline = CompletableFuture.supplyAsync(() -> 100)
.thenApplyAsync(result -> result * 2) // 异步转换
.thenCompose(value -> CompletableFuture.supplyAsync(() -> "结果:" + value))
.handle((result, ex) -> ex != null ? "默认值" : result); // 异常处理
2. Semaphore高级模式
// 资源池实现
class ConnectionPool {
private final Semaphore semaphore;
private final BlockingQueue<Connection> pool;
public ConnectionPool(int size) {
semaphore = new Semaphore(size, true); // 公平模式
pool = new ArrayBlockingQueue<>(size);
for (int i = 0; i < size; i++) {
pool.add(createConnection());
}
}
public Connection acquire() throws InterruptedException {
semaphore.acquire(); // 获取访问许可
return pool.take(); // 获取实际资源
}
public void release(Connection conn) {
pool.offer(conn); // 归还资源
semaphore.release(); // 释放许可
}
}
// 动态调整许可数
public void resize(int newSize) {
int delta = newSize - semaphore.availablePermits();
if (delta > 0) {
semaphore.release(delta); // 增加许可
} else {
semaphore.reducePermits(-delta); // 减少许可
}
}
3. 监控与调试
// CompletableFuture链监控
pipeline.whenComplete((res, ex) -> {
if (ex != null) {
logger.error("Pipeline failed", ex);
} else {
logger.info("Pipeline result: {}", res);
}
});
// Semaphore状态监控
public void monitorSemaphore(Semaphore sem) {
System.out.println("可用许可: " + sem.availablePermits());
System.out.println("等待线程数: " + sem.getQueueLength());
}
// 统一异常处理
CompletableFuture.supplyAsync(() -> {
// 业务代码
}).exceptionally(ex -> {
metrics.counter("async_errors").increment();
return fallbackValue();
});
生产环境建议:
-
使用-Djdk.tracePinnedThreads参数检测CompletableFuture线程阻塞
-
重要业务实现熔断降级机制,避免级联故障
-
对Semaphore设置监控告警(许可证不足、等待队列过长)
-
使用MDC(Mapped Diagnostic Context)传递异步任务上下文