From 52946be558e5cd6f41ce334387f9dd488995764a Mon Sep 17 00:00:00 2001 From: SerLiunx-ctrl <17689543@qq.com> Date: Thu, 6 Feb 2025 11:11:25 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=E5=B9=B6=E5=8F=91?= =?UTF-8?q?=E5=9E=8B=E7=8A=B6=E6=80=81=E6=9C=BA(=E5=9F=BA=E4=BA=8ECAS?= =?UTF-8?q?=E5=AE=9E=E7=8E=B0,=20=E6=9C=AA=E5=AE=8C=E6=88=90).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../machine/ConcurrentStateMachine.java | 11 ++ .../DefaultConcurrentStateMachine.java | 132 ++++++++++++++++++ .../statemanagement/machine/StateMachine.java | 3 + .../machine/StateMachineBuilder.java | 3 + .../manager/AbstractStateManager.java | 15 ++ .../statemanagement/manager/StateManager.java | 6 + .../serliunx/statemanagement/MachineTest.java | 1 + 7 files changed, 171 insertions(+) create mode 100644 src/main/java/com/serliunx/statemanagement/machine/ConcurrentStateMachine.java create mode 100644 src/main/java/com/serliunx/statemanagement/machine/DefaultConcurrentStateMachine.java diff --git a/src/main/java/com/serliunx/statemanagement/machine/ConcurrentStateMachine.java b/src/main/java/com/serliunx/statemanagement/machine/ConcurrentStateMachine.java new file mode 100644 index 0000000..2c40e51 --- /dev/null +++ b/src/main/java/com/serliunx/statemanagement/machine/ConcurrentStateMachine.java @@ -0,0 +1,11 @@ +package com.serliunx.statemanagement.machine; + +/** + * @author SerLiunx + * @version 1.0.0 + * @since 2025/2/6 + */ +public interface ConcurrentStateMachine extends StateMachine { + + boolean compareAndSet(S expectedValue, S newValue); +} diff --git a/src/main/java/com/serliunx/statemanagement/machine/DefaultConcurrentStateMachine.java b/src/main/java/com/serliunx/statemanagement/machine/DefaultConcurrentStateMachine.java new file mode 100644 index 0000000..8e5bbcd --- /dev/null +++ b/src/main/java/com/serliunx/statemanagement/machine/DefaultConcurrentStateMachine.java @@ -0,0 +1,132 @@ +package com.serliunx.statemanagement.machine; + +import com.serliunx.statemanagement.machine.handler.StateHandlerWrapper; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Consumer; + +/** + * @author SerLiunx + * @version 1.0.0 + * @since 2025/2/6 + */ +public class DefaultConcurrentStateMachine extends AbstractStateMachine implements ConcurrentStateMachine { + + /** + * 当前状态 + */ + private final AtomicInteger index = new AtomicInteger(0); + + DefaultConcurrentStateMachine(List stateList, + Map>> entryHandlers, + Map>> leaveHandlers, + Map>> exchangeHandlers, + Map>>> eventRegistries, + Executor executor, + Boolean async) { + super(stateList, entryHandlers, leaveHandlers, exchangeHandlers, eventRegistries, executor, async); + } + + @Override + public boolean compareAndSet(S expectedValue, S newValue) { + int current = indexOf(expectedValue); + int newIndex = indexOf(newValue); + if (current == -1 || newIndex == -1) + return false; + return index.compareAndSet(current, newIndex); + } + + /** + * 使用CAS不断尝试将当前状态重置回默认值(0) + * + * @param invokeHandlers 是否唤醒状态处理器 + */ + @Override + public void reset(boolean invokeHandlers) { + if (isDefault()) + return; + exchangeToTarget(0); + // TODO invokeHandlers + } + + @Override + public boolean switchTo(S state, boolean invokeHandlers) { + int i = indexOf(state); + if (i == -1 || + i == index.get()) { + return false; + } + exchangeToTarget(i); + return true; + } + + @Override + public S switchPrevAndGet(boolean invokeHandlers) { + S oldState = get(index.get()); + + S newState = get(index.get()); + if (invokeHandlers) + invokeHandlers(oldState, newState); + return newState; + } + + @Override + public S getAndSwitchPrev(boolean invokeHandlers) { + return super.getAndSwitchPrev(invokeHandlers); + } + + @Override + public void switchPrev(boolean invokeHandlers) { + super.switchPrev(invokeHandlers); + } + + @Override + public S switchNextAndGet(boolean invokeHandlers) { + return super.switchNextAndGet(invokeHandlers); + } + + @Override + public S getAndSwitchNext(boolean invokeHandlers) { + return super.getAndSwitchNext(invokeHandlers); + } + + @Override + public void switchNext(boolean invokeHandlers) { + super.switchNext(invokeHandlers); + } + + @Override + public void publish(Object event) { + + } + + /** + * 是否为默认状态 + */ + private boolean isDefault() { + return index.get() == 0; + } + + /** + * 移动下标至上一个状态 + */ + public void exchangeToPrev() { + final int size = size(); + } + + /** + * 切换到指定状态值 + *
  • 使用CAS一直尝试, 直到成功 + * + * @param target 目标值 + */ + private void exchangeToTarget(int target) { + int currentValue; + do { + currentValue = index.get(); + } while (!index.compareAndSet(currentValue, target)); + } +} diff --git a/src/main/java/com/serliunx/statemanagement/machine/StateMachine.java b/src/main/java/com/serliunx/statemanagement/machine/StateMachine.java index 4f2fc1f..84a8c6a 100644 --- a/src/main/java/com/serliunx/statemanagement/machine/StateMachine.java +++ b/src/main/java/com/serliunx/statemanagement/machine/StateMachine.java @@ -100,4 +100,7 @@ public interface StateMachine extends BidirectionalStateManager, AutoClose * @return 切换成功返回真, 否则返回假 */ boolean switchTo(S state); + + @Override + default void close() throws Exception {} } diff --git a/src/main/java/com/serliunx/statemanagement/machine/StateMachineBuilder.java b/src/main/java/com/serliunx/statemanagement/machine/StateMachineBuilder.java index f64e2d0..087a4cf 100644 --- a/src/main/java/com/serliunx/statemanagement/machine/StateMachineBuilder.java +++ b/src/main/java/com/serliunx/statemanagement/machine/StateMachineBuilder.java @@ -253,6 +253,9 @@ public final class StateMachineBuilder { if (type.equals(StateMachineType.STANDARD)) { return (M)new StandardStateMachine<>(stateList, entryHandlers, leaveHandlers, exchangeHandlers, eventRegistries, executor, async); + } else if (type.equals(StateMachineType.CONCURRENT)) { + return (M)new DefaultConcurrentStateMachine<>(stateList, entryHandlers, + leaveHandlers, exchangeHandlers, eventRegistries, executor, async); } throw new IllegalArgumentException("未知的状态机类型: " + type); } diff --git a/src/main/java/com/serliunx/statemanagement/manager/AbstractStateManager.java b/src/main/java/com/serliunx/statemanagement/manager/AbstractStateManager.java index 0ced3a5..b96615c 100644 --- a/src/main/java/com/serliunx/statemanagement/manager/AbstractStateManager.java +++ b/src/main/java/com/serliunx/statemanagement/manager/AbstractStateManager.java @@ -100,6 +100,11 @@ public abstract class AbstractStateManager implements StateManager { } } + @Override + public int size() { + return stateList.size(); + } + @Override public boolean isSwitchable() { return stateList.size() > 1; @@ -140,6 +145,16 @@ public abstract class AbstractStateManager implements StateManager { return stateList.get(index); } + /** + * 获取指定下标的状态 + * + * @param index 下标 + * @return 状态 + */ + protected S get(int index) { + return stateList.get(index); + } + /** * 获取指定状态在状态列表中的序号 * diff --git a/src/main/java/com/serliunx/statemanagement/manager/StateManager.java b/src/main/java/com/serliunx/statemanagement/manager/StateManager.java index 9fc63aa..dcada0b 100644 --- a/src/main/java/com/serliunx/statemanagement/manager/StateManager.java +++ b/src/main/java/com/serliunx/statemanagement/manager/StateManager.java @@ -31,6 +31,12 @@ public interface StateManager { */ void reset(); + /** + * 获取当前状态数量 + * @return 数量 + */ + int size(); + /** * 是否可切换 * diff --git a/src/test/java/com/serliunx/statemanagement/MachineTest.java b/src/test/java/com/serliunx/statemanagement/MachineTest.java index 509ca06..1359ad8 100644 --- a/src/test/java/com/serliunx/statemanagement/MachineTest.java +++ b/src/test/java/com/serliunx/statemanagement/MachineTest.java @@ -1,5 +1,6 @@ package com.serliunx.statemanagement; +import com.serliunx.statemanagement.machine.ConcurrentStateMachine; import com.serliunx.statemanagement.machine.StateMachine; import com.serliunx.statemanagement.machine.StateMachineBuilder; import com.serliunx.statemanagement.support.PrinterEvent;