From 3a4db562ced6cd0bd1bbe34239a6cce9d0178f67 Mon Sep 17 00:00:00 2001 From: SerLiunx-ctrl <17689543@qq.com> Date: Thu, 6 Feb 2025 15:28:14 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=8C=E5=96=84=E5=B9=B6=E5=8F=91?= =?UTF-8?q?=E5=9E=8B=E7=8A=B6=E6=80=81=E6=9C=BA.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../machine/ConcurrentStateMachine.java | 22 +++++ .../DefaultConcurrentStateMachine.java | 83 ++++++++++++++++--- .../serliunx/statemanagement/MachineTest.java | 14 ++++ 3 files changed, 108 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/serliunx/statemanagement/machine/ConcurrentStateMachine.java b/src/main/java/com/serliunx/statemanagement/machine/ConcurrentStateMachine.java index 2c40e51..cc3cfa8 100644 --- a/src/main/java/com/serliunx/statemanagement/machine/ConcurrentStateMachine.java +++ b/src/main/java/com/serliunx/statemanagement/machine/ConcurrentStateMachine.java @@ -1,11 +1,33 @@ package com.serliunx.statemanagement.machine; /** + * 基本行为与{@link StateMachine} 一致, 最大不同是切换状态不再使用直接的锁机制, 具体由实现类决定 + *
  • 默认实现{@link DefaultConcurrentStateMachine}, 状态切换序列由CAS实现. + * * @author SerLiunx * @version 1.0.0 * @since 2025/2/6 + * @see DefaultConcurrentStateMachine */ public interface ConcurrentStateMachine extends StateMachine { + /** + * 尝试使用CAS更新状态 + *
  • 无论是否成功更新都不触发状态处理器 + * + * @param expectedValue 前置状态 + * @param newValue 更新的状态值 + * @return 成功更新返回真, 否则返回假 + */ boolean compareAndSet(S expectedValue, S newValue); + + /** + * 尝试使用CAS更新状态 + * + * @param expectedValue 前置状态 + * @param newValue 更新的状态值 + * @param invokeHandlers 是否触发状态处理器, 仅在成功更新时才触发 + * @return 成功更新返回真, 否则返回假 + */ + boolean compareAndSet(S expectedValue, S newValue, boolean invokeHandlers); } diff --git a/src/main/java/com/serliunx/statemanagement/machine/DefaultConcurrentStateMachine.java b/src/main/java/com/serliunx/statemanagement/machine/DefaultConcurrentStateMachine.java index 8e5bbcd..1e20b10 100644 --- a/src/main/java/com/serliunx/statemanagement/machine/DefaultConcurrentStateMachine.java +++ b/src/main/java/com/serliunx/statemanagement/machine/DefaultConcurrentStateMachine.java @@ -9,6 +9,8 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; /** + * 并发型状态机的默认实现, 内置的状态序列切换使用CAS实现. + * * @author SerLiunx * @version 1.0.0 * @since 2025/2/6 @@ -32,11 +34,24 @@ public class DefaultConcurrentStateMachine extends AbstractStateMachine im @Override public boolean compareAndSet(S expectedValue, S newValue) { + return compareAndSet(expectedValue, newValue, false); + } + + @Override + public boolean compareAndSet(S expectedValue, S newValue, boolean invokeHandlers) { int current = indexOf(expectedValue); int newIndex = indexOf(newValue); if (current == -1 || newIndex == -1) return false; - return index.compareAndSet(current, newIndex); + + S oldState = get(index.get()); + boolean result = index.compareAndSet(current, newIndex); + if (result && invokeHandlers) { + S newState = get(index.get()); + invokeHandlers(oldState, newState); + } + + return result; } /** @@ -48,8 +63,11 @@ public class DefaultConcurrentStateMachine extends AbstractStateMachine im public void reset(boolean invokeHandlers) { if (isDefault()) return; + S oldState = get(index.get()); exchangeToTarget(0); - // TODO invokeHandlers + S newState = get(index.get()); + if (invokeHandlers) + invokeHandlers(oldState, newState); } @Override @@ -59,14 +77,17 @@ public class DefaultConcurrentStateMachine extends AbstractStateMachine im i == index.get()) { return false; } + S oldState = get(index.get()); exchangeToTarget(i); + if (invokeHandlers) + invokeHandlers(oldState, state); return true; } @Override public S switchPrevAndGet(boolean invokeHandlers) { S oldState = get(index.get()); - + exchangeToPrev(); S newState = get(index.get()); if (invokeHandlers) invokeHandlers(oldState, newState); @@ -75,27 +96,50 @@ public class DefaultConcurrentStateMachine extends AbstractStateMachine im @Override public S getAndSwitchPrev(boolean invokeHandlers) { - return super.getAndSwitchPrev(invokeHandlers); + S oldState = get(index.get()); + exchangeToPrev(); + S newState = get(index.get()); + if (invokeHandlers) + invokeHandlers(oldState, newState); + return oldState; } @Override public void switchPrev(boolean invokeHandlers) { - super.switchPrev(invokeHandlers); + S oldState = get(index.get()); + exchangeToPrev(); + S newState = get(index.get()); + if (invokeHandlers) + invokeHandlers(oldState, newState); } @Override public S switchNextAndGet(boolean invokeHandlers) { - return super.switchNextAndGet(invokeHandlers); + S oldState = get(index.get()); + exchangeToNext(); + S newState = get(index.get()); + if (invokeHandlers) + invokeHandlers(oldState, newState); + return newState; } @Override public S getAndSwitchNext(boolean invokeHandlers) { - return super.getAndSwitchNext(invokeHandlers); + S oldState = get(index.get()); + exchangeToNext(); + S newState =get(index.get()); + if (invokeHandlers) + invokeHandlers(oldState, newState); + return oldState; } @Override public void switchNext(boolean invokeHandlers) { - super.switchNext(invokeHandlers); + S oldState = get(index.get()); + exchangeToNext(); + S newState = get(index.get()); + if (invokeHandlers) + invokeHandlers(oldState, newState); } @Override @@ -106,15 +150,32 @@ public class DefaultConcurrentStateMachine extends AbstractStateMachine im /** * 是否为默认状态 */ - private boolean isDefault() { + protected boolean isDefault() { return index.get() == 0; } /** * 移动下标至上一个状态 + *
  • 使用CAS一直尝试, 直到成功 */ - public void exchangeToPrev() { + protected void exchangeToPrev() { final int size = size(); + int currentValue; + do { + currentValue = index.get(); + } while (!index.compareAndSet(currentValue, currentValue == 0 ? size - 1 : currentValue - 1)); + } + + /** + * 移动下标至下一个状态 + *
  • 使用CAS一直尝试, 直到成功 + */ + protected void exchangeToNext() { + final int size = size(); + int currentValue; + do { + currentValue = index.get(); + } while (!index.compareAndSet(currentValue, currentValue == size - 1 ? 0 : currentValue + 1)); } /** @@ -123,7 +184,7 @@ public class DefaultConcurrentStateMachine extends AbstractStateMachine im * * @param target 目标值 */ - private void exchangeToTarget(int target) { + protected void exchangeToTarget(int target) { int currentValue; do { currentValue = index.get(); diff --git a/src/test/java/com/serliunx/statemanagement/MachineTest.java b/src/test/java/com/serliunx/statemanagement/MachineTest.java index 1359ad8..a0a09b3 100644 --- a/src/test/java/com/serliunx/statemanagement/MachineTest.java +++ b/src/test/java/com/serliunx/statemanagement/MachineTest.java @@ -48,4 +48,18 @@ public class MachineTest { stateMachine.close(); } + + @Test + public void testConcurrentStateMachine() throws Exception { + ConcurrentStateMachine stateMachine = StateMachineBuilder.from(PrinterState.values()) + .whenEntry(PrinterState.STOPPING, h -> { + System.out.println(1111); + }) + .concurrent() + .build(); + + System.out.println(stateMachine.compareAndSet(PrinterState.IDLE, PrinterState.STOPPING, true)); + + stateMachine.close(); + } }