状态机轮转的偶发性bug举例与修复策略

// 场景1:状态检查和更新不是原子操作,导致竞态条件
public class RaceConditionBug {
    private volatile TaskState state = TaskState.PENDING;
    
    // 问题代码
    public void processTaskWithBug(String taskId) {
        // 检查和更新之间可能有其他线程修改状态
        if (state == TaskState.PENDING) {
            // 这里可能被其他线程中断
            Thread.sleep(100); // 模拟一些处理
            state = TaskState.RUNNING; // 状态可能已经被其他线程改变
        }
    }
    
    // 修复方案:使用同步块
    public void processTaskFixed(String taskId) {
        synchronized (this) {
            if (state == TaskState.PENDING) {
                state = TaskState.RUNNING;
            }
        }
    }
}

// 场景2:事件处理顺序依赖导致的问题
public class EventOrderingBug {
    private BlockingQueue<StateEvent> eventQueue = new LinkedBlockingQueue<>();
    private volatile TaskState state = TaskState.PENDING;
    
    // 问题代码
    public void handleEventsWithBug() {
        executor.submit(() -> {
            StateEvent event1 = eventQueue.take();
            processEvent(event1); // 处理第一个事件
        });
        
        executor.submit(() -> {
            StateEvent event2 = eventQueue.take();
            processEvent(event2); // 可能在event1之前处理
        });
    }
    
    // 修复方案:使用单线程处理保证顺序
    private final ExecutorService singleThreadExecutor = 
        Executors.newSingleThreadExecutor();
    
    public void handleEventsFixed() {
        singleThreadExecutor.submit(() -> {
            while (true) {
                StateEvent event = eventQueue.take();
                processEvent(event); // 按队列顺序处理
            }
        });
    }
}

// 场景3:状态转换过程中的中断问题
public class StateTransitionBug {
    private Lock stateLock = new ReentrantLock();
    private TaskState state = TaskState.PENDING;
    
    // 问题代码
    public void transitWithBug(TaskState newState) {
        try {
            stateLock.lock();
            validateTransition(state, newState); // 可能抛出异常
            updateState(newState); // 如果上面抛异常,状态可能不一致
        } finally {
            stateLock.unlock();
        }
    }
    
    // 修复方案:使用事务性的状态转换
    @Transactional
    public void transitFixed(TaskState newState) {
        TaskEntity task = taskRepository.findById(taskId)
            .orElseThrow(() -> new TaskNotFoundException(taskId));
        
        validateTransition(task.getState(), newState);
        task.setState(newState);
        taskRepository.save(task);
        publishStateChangeEvent(task);
    }
}

// 场景4:非幂等的状态转换
public class NonIdempotentBug {
    // 问题代码
    public void completeTaskWithBug(String taskId) {
        TaskEntity task = taskRepository.findById(taskId).get();
        task.setState(TaskState.COMPLETED);
        task.setCompletionCount(task.getCompletionCount() + 1); // 多次调用会累加
        taskRepository.save(task);
    }
    
    // 修复方案:实现幂等性
    public void completeTaskFixed(String taskId) {
        taskRepository.updateTaskState(
            taskId, 
            TaskState.RUNNING,  // 预期的当前状态
            TaskState.COMPLETED // 目标状态
        );
    }
}

// 场景5:分布式环境下的状态同步问题
public class DistributedStateBug {
    // 问题代码
    public void processDistributedTaskWithBug(String taskId) {
        TaskEntity task = taskRepository.findById(taskId).get();
        if (task.getState() == TaskState.PENDING) {
            // 其他节点可能已经在处理
            task.setState(TaskState.RUNNING);
            taskRepository.save(task);
        }
    }
    
    // 修复方案:使用分布式锁
    private final DistributedLock distributedLock;
    
    public void processDistributedTaskFixed(String taskId) {
        try {
            if (distributedLock.tryLock(taskId, 5, TimeUnit.SECONDS)) {
                try {
                    TaskEntity task = taskRepository.findById(taskId).get();
                    if (task.getState() == TaskState.PENDING) {
                        task.setState(TaskState.RUNNING);
                        taskRepository.save(task);
                    }
                } finally {
                    distributedLock.unlock(taskId);
                }
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new TaskProcessingException("Failed to acquire lock", e);
        }
    }
}

// 场景6:状态转换的一致性问题
public class StateConsistencyBug {
    // 问题代码
    public void updateRelatedStatesWithBug(String taskId) {
        // 更新主任务状态
        TaskEntity task = taskRepository.findById(taskId).get();
        task.setState(TaskState.COMPLETED);
        taskRepository.save(task);
        
        // 更新子任务状态可能失败
        List<SubTaskEntity> subTasks = subTaskRepository.findByParentId(taskId);
        for (SubTaskEntity subTask : subTasks) {
            subTask.setState(TaskState.COMPLETED);
            subTaskRepository.save(subTask); // 可能抛出异常
        }
    }
    
    // 修复方案:使用事务确保一致性
    @Transactional
    public void updateRelatedStatesFixed(String taskId) {
        TaskEntity task = taskRepository.findById(taskId).get();
        List<SubTaskEntity> subTasks = subTaskRepository.findByParentId(taskId);
        
        // 在一个事务中更新所有相关状态
        task.setState(TaskState.COMPLETED);
        taskRepository.save(task);
        
        for (SubTaskEntity subTask : subTasks) {
            subTask.setState(TaskState.COMPLETED);
            subTaskRepository.save(subTask);
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值