并发设计模式实战系列(10):Balking(犹豫模式)

简介: 🌟 大家好,我是摘星!🌟今天为大家带来的是并发设计模式实战系列,第10章,废话不多说直接开始~


image.gif 编辑

🌟 大家好,我是摘星! 🌟

今天为大家带来的是并发设计模式实战系列,第10章Balking(犹豫模式),废话不多说直接开始~

目录

一、核心原理深度拆解

1. 状态守护机制

2. 与状态模式的区别

二、生活化类比:自动售货机

三、Java代码实现(生产级Demo)

1. 完整可运行代码

2. 关键实现技术

四、横向对比表格

1. 相似模式对比

2. 线程安全方案选择

五、高级应用技巧

1. 组合模式增强

2. 日志增强实现

3. Spring应用场景

六、Balking模式变体与扩展(续)

1. 分布式场景下的Balking

2. 分级Balking策略

七、性能优化与陷阱规避

1. 状态检查的性能优化

2. 常见陷阱与解决方案

八、工业级应用案例

1. Tomcat连接器中的Balking

2. 电商库存扣减场景

九、与其他模式的组合应用

1. Balking + Observer 模式

2. Balking + Chain of Responsibility

十、终极对比表格:Balking模式家族


一、核心原理深度拆解

1. 状态守护机制

┌───────────────┐       ┌───────────────┐
│   Client      │──────>│   GuardedObj   │
└───────────────┘       ├───────────────┤
                         │ - state       │
                         │ - checkState()│
                         │ - changeState() 
                         └───────────────┘

image.gif

  • 状态检查:通过原子操作验证对象是否处于可处理状态
  • 条件拦截:当状态不满足时立即放弃操作(Balking)
  • 线程安全:所有状态变更必须加锁(synchronized或CAS)

2. 与状态模式的区别

  • Balking:直接放弃不符合条件的请求(快速失败)
  • State Pattern:将行为委托给不同状态对象处理

二、生活化类比:自动售货机

系统组件

现实类比

核心行为

Client

顾客投币

发起购买请求

checkState

货品检测系统

检查库存和金额是否充足

Balking

退币机制

条件不满足时立即退币

  • 典型场景:当检测到「缺货」或「金额不足」时,立即终止交易流程

三、Java代码实现(生产级Demo)

1. 完整可运行代码

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();
    }
}

image.gif

2. 关键实现技术

// 1. 原子状态标记
private final AtomicBoolean changed = new AtomicBoolean(false);
// 2. 状态检查与重置一体化操作
changed.getAndSet(false) 
// 3. 线程安全计数器
autoSaveCount.incrementAndGet()

image.gif


四、横向对比表格

1. 相似模式对比

模式

核心策略

适用场景

Balking

条件不满足立即放弃

状态校验场景(如自动保存)

Retry

条件不满足循环重试

网络请求等可恢复场景

State

委托给状态对象处理

复杂状态转换场景

Guard Suspension

等待条件满足

必须完成的阻塞任务

2. 线程安全方案选择

实现方式

优点

缺点

synchronized

简单可靠

性能开销较大

AtomicXXX

无锁高性能

只适用于简单状态

ReentrantLock

可中断/超时

需手动释放锁

volatile

轻量级可见性保证

不保证复合操作原子性


五、高级应用技巧

1. 组合模式增强

// 结合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();
}

image.gif

2. 日志增强实现

// 记录Balking事件
if (!changed.get()) {
    auditLogger.log("Balking at " + LocalDateTime.now());
    return;
}

image.gif

3. Spring应用场景

@Component
public class ConfigMonitor {
    @Scheduled(fixedRate = 5000)
    public void reloadConfig() {
        if (!GlobalConfig.isDirty()) {
            return; // Balking
        }
        // 重新加载配置...
    }
}

image.gif

好的!我将延续原有结构,从 第六部分 开始扩展Balking模式的深度内容,保持技术解析的连贯性和完整性。


六、Balking模式变体与扩展(续)

1. 分布式场景下的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;
    }
}

image.gif

关键点

  • 使用Redis的SETNX命令替代本地原子变量
  • 需设置过期时间避免死锁
  • 适用于微服务抢单、定时任务调度等场景

2. 分级Balking策略

// 根据业务重要性实现分级放弃
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();
        }
        // 执行处理...
    }
}

image.gif


七、性能优化与陷阱规避

1. 状态检查的性能优化

优化手段

实现方式

适用场景

双重检查锁

先非阻塞检查,再同步块内二次检查

高并发读场景

状态标记分组

对不同资源分桶标记

多资源竞争场景

延迟状态重置

处理完成后再重置状态(减少CAS竞争)

短时高频状态变更

// 双重检查锁实现示例
public class DoubleCheckBalking {
    private volatile boolean busy = false;
    
    public void execute() {
        if (!busy) {  // 第一次非阻塞检查
            synchronized (this) {
                if (!busy) {  // 第二次原子检查
                    busy = true;
                    // 执行任务...
                    busy = false;
                }
            }
        }
    }
}

image.gif

2. 常见陷阱与解决方案

陷阱现象

根本原因

解决方案

活锁(Livelock)

多个线程持续检查-放弃循环

引入随机退避时间

状态逃逸

对象引用被外部修改

防御性拷贝(Deep Copy)

监控缺失

无法追踪放弃操作次数

添加Metrics计数器


八、工业级应用案例

1. Tomcat连接器中的Balking

// org.apache.tomcat.util.net.AbstractEndpoint
public boolean processSocket(SocketWrapperBase<S> socket) {
    if (running && !paused) {
        // 将socket交给线程池处理
        return executor.execute(new SocketProcessor(socket));
    }
    // 服务未运行立即放弃
    return false; 
}

image.gif

设计启示

  • 通过runningpaused双状态判断
  • 放弃时直接关闭Socket连接释放资源

2. 电商库存扣减场景

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);
    }
}

image.gif


九、与其他模式的组合应用

1. Balking + Observer 模式

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();
    }
}

image.gif

2. Balking + Chain of Responsibility

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);
}

image.gif


十、终极对比表格:Balking模式家族

变体名称

核心差异点

典型应用场景

Java SDK中的体现

经典Balking

基于本地原子变量

单机资源控制

AtomicBoolean.getAndSet

分布式Balking

依赖外部存储状态

跨服务协调

Redis SETNX

分级Balking

按优先级差异化处理

业务流量分级

ThreadPoolExecutor拒绝策略

延迟Balking

超时后才放弃

弱依赖服务调用

Future.get(timeout)

批量Balking

累积多个请求后统一判断

批量处理系统

BufferedWriter.flush

目录
相关文章
|
1月前
|
设计模式 消息中间件 监控
并发设计模式实战系列(5):生产者/消费者
🌟 ​大家好,我是摘星!​ 🌟今天为大家带来的是并发设计模式实战系列,第五章,废话不多说直接开始~
79 1
|
1月前
|
设计模式 负载均衡 监控
并发设计模式实战系列(2):领导者/追随者模式
🌟 ​大家好,我是摘星!​ 🌟今天为大家带来的是并发设计模式实战系列,第二章领导者/追随者(Leader/Followers)模式,废话不多说直接开始~
51 0
|
1月前
|
设计模式 监控 Java
并发设计模式实战系列(1):半同步/半异步模式
🌟 ​大家好,我是摘星!​ 🌟今天为大家带来的是并发设计模式实战系列,第一章半同步/半异步(Half-Sync/Half-Async)模式,废话不多说直接开始~
41 0
|
1月前
|
设计模式 运维 监控
并发设计模式实战系列(4):线程池
需要建立持续的性能剖析(Profiling)和调优机制。通过以上十二个维度的系统化扩展,构建了一个从。设置合理队列容量/拒绝策略。动态扩容/优化任务处理速度。检查线程栈定位热点代码。调整最大用户进程数限制。CPU占用率100%
153 0
|
1月前
|
设计模式 存储 安全
并发设计模式实战系列(7):Thread Local Storage (TLS)
🌟 大家好,我是摘星! 🌟今天为大家带来的是并发设计模式实战系列,第七章Thread Local Storage (TLS),废话不多说直接开始~
68 0
|
1月前
|
设计模式 消息中间件 监控
并发设计模式实战系列(3):工作队列
🌟 ​大家好,我是摘星!​ 🌟今天为大家带来的是并发设计模式实战系列,第三章,废话不多说直接开始~
34 0
|
1月前
|
设计模式 监控 Java
并发设计模式实战系列(6):读写锁
🌟 ​大家好,我是摘星!​ 🌟今天为大家带来的是并发设计模式实战系列,第六章,废话不多说直接开始~
33 0
|
1月前
|
设计模式 Java 数据库连接
【设计模式】【创建型模式】工厂方法模式(Factory Methods)
一、入门 什么是工厂方法模式? 工厂方法模式(Factory Method Pattern)是一种创建型设计模式,它定义了一个用于创建对象的接口,但由子类决定实例化哪个类。工厂方法模式使类的实例化延迟
79 16
|
1月前
|
设计模式 安全 Java
并发设计模式实战系列(12):不变模式(Immutable Object)
🌟 大家好,我是摘星!🌟今天为大家带来的是并发设计模式实战系列,第十二章,废话不多说直接开始~
35 0
|
24天前
|
设计模式 算法 Java
设计模式觉醒系列(04)策略模式|简单工厂模式的升级版
本文介绍了简单工厂模式与策略模式的概念及其融合实践。简单工厂模式用于对象创建,通过隐藏实现细节简化代码;策略模式关注行为封装与切换,支持动态替换算法,增强灵活性。两者结合形成“策略工厂”,既简化对象创建又保持低耦合。文章通过支付案例演示了模式的应用,并强调实际开发中应根据需求选择合适的设计模式,避免生搬硬套。最后推荐了JVM调优、并发编程等技术专题,助力开发者提升技能。