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