今天为大家带来的是并发设计模式实战系列,第10章Balking(犹豫模式),废话不多说直接开始~
┌───────────────┐ ┌───────────────┐
│ Client │──────>│ GuardedObj │
└───────────────┘ ├───────────────┤
│ - state │
│ - checkState()│
│ - changeState()
└───────────────┘
系统组件 | 现实类比 | 核心行为 |
---|---|---|
Client | 顾客投币 | 发起购买请求 |
checkState | 货品检测系统 | 检查库存和金额是否充足 |
Balking | 退币机制 | 条件不满足时立即退币 |
import java.util.concurrent.atomic.*;
// 带Balking模式的文件自动保存
public class AutoSaveEditor {
// 状态标记(原子操作)
private final AtomicBoolean changed = new AtomicBoolean(false);
private final AtomicInteger autoSaveCount = new AtomicInteger(0);
// 状态守护方法
public void autoSave() {
// STEP 1: 状态检查
if (!changed.getAndSet(false)) {
System.out.println("[Balking] 无修改不保存");
return; // 快速返回
}
// STEP 2: 实际保存操作
doSave();
}
// 修改内容后触发状态变更
public void editDocument(String newContent) {
System.out.println("编辑内容: " + newContent);
changed.set(true);
}
private void doSave() {
System.out.println("自动保存第" + autoSaveCount.incrementAndGet() + "次...");
// 模拟IO操作
try { Thread.sleep(500); }
catch (InterruptedException e) {}
}
// 测试用例
public static void main(String[] args) throws InterruptedException {
AutoSaveEditor editor = new AutoSaveEditor();
// 第一次修改(应触发保存)
editor.editDocument("Version1");
editor.autoSave();
// 连续修改不保存(状态被消费)
editor.editDocument("Version2");
editor.editDocument("Version3");
editor.autoSave(); // 只会保存一次
// 无修改情况
editor.autoSave();
}
}
// 1. 原子状态标记
private final AtomicBoolean changed = new AtomicBoolean(false);
// 2. 状态检查与重置一体化操作
changed.getAndSet(false)
// 3. 线程安全计数器
autoSaveCount.incrementAndGet()
模式 | 核心策略 | 适用场景 |
---|---|---|
Balking | 条件不满足立即放弃 | 状态校验场景(如自动保存) |
Retry | 条件不满足循环重试 | 网络请求等可恢复场景 |
State | 委托给状态对象处理 | 复杂状态转换场景 |
Guard Suspension | 等待条件满足 | 必须完成的阻塞任务 |
实现方式 | 优点 | 缺点 |
---|---|---|
synchronized | 简单可靠 | 性能开销较大 |
AtomicXXX | 无锁高性能 | 只适用于简单状态 |
ReentrantLock | 可中断/超时 | 需手动释放锁 |
volatile | 轻量级可见性保证 | 不保证复合操作原子性 |
// 结合Guard Suspension模式实现超时控制
public boolean autoSaveWithTimeout(long timeout) throws InterruptedException {
long start = System.currentTimeMillis();
while (!changed.get()) {
if (System.currentTimeMillis() - start > timeout) {
return false; // 超时放弃
}
Thread.sleep(50);
}
return doSave();
}
// 记录Balking事件
if (!changed.get()) {
auditLogger.log("Balking at " + LocalDateTime.now());
return;
}
@Component
public class ConfigMonitor {
@Scheduled(fixedRate = 5000)
public void reloadConfig() {
if (!GlobalConfig.isDirty()) {
return; // Balking
}
// 重新加载配置...
}
}
好的!我将延续原有结构,从 第六部分 开始扩展Balking模式的深度内容,保持技术解析的连贯性和完整性。
// 使用Redis实现分布式状态标记
public class DistributedBalking {
private final Jedis jedis;
private static final String LOCK_KEY = "resource:lock";
public boolean tryProcess(String resourceId) {
// SETNX实现原子状态检查(分布式锁原理)
Long result = jedis.setnx(LOCK_KEY, "locked");
if (result == 0) {
System.out.println("[Distributed Balking] 资源已被占用");
return false;
}
jedis.expire(LOCK_KEY, 30);
return true;
}
}
关键点:
SETNX
命令替代本地原子变量// 根据业务重要性实现分级放弃
public class PriorityBalking {
private enum Priority { HIGH, NORMAL, LOW }
public void process(Priority priority) {
if (!checkResource()) {
if (priority == Priority.LOW) {
System.out.println("低优先级任务放弃");
return;
}
// 高优先级任务等待资源
waitForResource();
}
// 执行处理...
}
}
优化手段 | 实现方式 | 适用场景 |
---|---|---|
双重检查锁 | 先非阻塞检查,再同步块内二次检查 | 高并发读场景 |
状态标记分组 | 对不同资源分桶标记 | 多资源竞争场景 |
延迟状态重置 | 处理完成后再重置状态(减少CAS竞争) | 短时高频状态变更 |
// 双重检查锁实现示例
public class DoubleCheckBalking {
private volatile boolean busy = false;
public void execute() {
if (!busy) { // 第一次非阻塞检查
synchronized (this) {
if (!busy) { // 第二次原子检查
busy = true;
// 执行任务...
busy = false;
}
}
}
}
}
陷阱现象 | 根本原因 | 解决方案 |
---|---|---|
活锁(Livelock) | 多个线程持续检查-放弃循环 | 引入随机退避时间 |
状态逃逸 | 对象引用被外部修改 | 防御性拷贝(Deep Copy) |
监控缺失 | 无法追踪放弃操作次数 | 添加Metrics计数器 |
// org.apache.tomcat.util.net.AbstractEndpoint
public boolean processSocket(SocketWrapperBase<S> socket) {
if (running && !paused) {
// 将socket交给线程池处理
return executor.execute(new SocketProcessor(socket));
}
// 服务未运行立即放弃
return false;
}
设计启示:
running
和paused
双状态判断public class InventoryService {
private final AtomicInteger stock = new AtomicInteger(100);
public boolean deductStock(int quantity) {
int current = stock.get();
if (current < quantity) {
// 库存不足立即返回
metrics.log("balking:insufficient_stock");
return false;
}
// CAS原子扣减
return stock.compareAndSet(current, current - quantity);
}
}
public class ConfigMonitor {
private final List<Listener> listeners = new CopyOnWriteArrayList<>();
private volatile String currentConfig;
// 配置变更通知(Balking条件检查)
public void updateConfig(String newConfig) {
if (Objects.equals(currentConfig, newConfig)) {
return; // 配置未变化时放弃
}
this.currentConfig = newConfig;
notifyListeners();
}
}
public abstract class OrderHandler {
private OrderHandler next;
public void handle(Order order) {
if (canHandle(order)) {
// 实际处理逻辑...
} else if (next != null) {
next.handle(order);
} else {
// 责任链终止时的Balking
order.fail("NO_HANDLER_FOUND");
}
}
protected abstract boolean canHandle(Order order);
}
变体名称 | 核心差异点 | 典型应用场景 | Java SDK中的体现 |
---|---|---|---|
经典Balking | 基于本地原子变量 | 单机资源控制 | AtomicBoolean.getAndSet |
分布式Balking | 依赖外部存储状态 | 跨服务协调 | Redis SETNX |
分级Balking | 按优先级差异化处理 | 业务流量分级 | ThreadPoolExecutor拒绝策略 |
延迟Balking | 超时后才放弃 | 弱依赖服务调用 | Future.get(timeout) |
批量Balking | 累积多个请求后统一判断 | 批量处理系统 | BufferedWriter.flush |
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有