Compare commits

23 Commits

Author SHA1 Message Date
f733e1ff5a doc: 文档标准化. 2025-05-16 17:16:50 +08:00
c0ccf2cb4f fix: 状态管理器switchToIfMatch方法逻辑异常. 2025-04-24 08:59:57 +08:00
cd24c7de99 feat: 新增默认方法、调整方法名及文档注释. 2025-04-23 17:19:58 +08:00
e2a58cf7bd fix: 0号位状态时向前切换失效. 2025-04-23 14:33:18 +08:00
1e9113666b feat: 状态机接口新增少量逻辑组合相关的默认方法. 2025-04-23 11:30:27 +08:00
d533061410 feat: 新增仅用于单元测试的日志输出. 2025-04-23 08:50:25 +08:00
961a496465 change: 丰富测试用例; 并发性状态机CAS默认触发状态处理器. 2025-04-15 16:47:47 +08:00
89799257aa feat: 新增相关工具类用来快速创建一个状态机. 2025-04-11 09:39:13 +08:00
bbde9acf55 fix: 状态机初始化状态逻辑失效. 2025-04-11 09:16:46 +08:00
cdfe94de08 change: clean. 2025-04-10 09:22:28 +08:00
92ee373ea4 feat: 抽象更高层的状态事件注册接口. 2025-03-28 14:51:10 +08:00
921520b097 doc: 修复注释错误. 2025-03-28 09:13:02 +08:00
f0db621968 feat: 状态机现可提供初始化状态. 2025-03-27 11:32:20 +08:00
5d73a20428 Merge remote-tracking branch 'origin/master' 2025-03-27 08:56:36 +08:00
974b0ffe6d change: 代码清理、注释修复. 2025-03-27 08:56:25 +08:00
19ef4f1262 Revert "change: 调整工程结构."
This reverts commit f6a3b336de.
2025-03-26 20:28:09 +08:00
f6a3b336de change: 调整工程结构. 2025-03-23 19:16:12 +08:00
494f093041 fix: 状态机CAS逻辑异常. 2025-03-07 10:28:05 +08:00
af9c1c9622 feat: 新增可计数的拒绝策略. 2025-03-05 14:50:36 +08:00
f7e4400e37 feat: 状态机事件触发现可异步执行. 2025-02-19 14:27:32 +08:00
101d440510 doc: 触发逻辑补充说明. 2025-02-19 14:12:59 +08:00
4a843f885e feat: 状态机内置默认用于异步执行事件的线程池. 2025-02-17 12:45:51 +08:00
4b4a6d27b3 change: 移除测试中的slf4j及lombok. 2025-02-06 19:41:04 +08:00
31 changed files with 925 additions and 247 deletions

View File

@@ -22,18 +22,12 @@
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<!-- 日志输出 (仅用于测试) -->
<dependency> <dependency>
<groupId>ch.qos.logback</groupId> <groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId> <artifactId>logback-classic</artifactId>
<version>1.2.13</version> <version>1.2.13</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.36</version>
<scope>test</scope>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@@ -1,6 +1,8 @@
package com.serliunx.statemanagement.exception; package com.serliunx.statemanagement.exception;
/** /**
* 状态机异常
*
* @author <a href="mailto:serliunx@yeah.net">SerLiunx</a> * @author <a href="mailto:serliunx@yeah.net">SerLiunx</a>
* @version 1.0.0 * @version 1.0.0
* @since 2024/12/28 * @since 2024/12/28

View File

@@ -1,14 +1,11 @@
package com.serliunx.statemanagement.machine; package com.serliunx.statemanagement.machine;
import com.serliunx.statemanagement.machine.handler.StateHandler;
import com.serliunx.statemanagement.machine.handler.StateHandlerProcessParams;
import com.serliunx.statemanagement.machine.handler.StateHandlerWrapper;
import com.serliunx.statemanagement.manager.AbstractStateManager; import com.serliunx.statemanagement.manager.AbstractStateManager;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer; import java.util.function.Consumer;
/** /**
@@ -20,27 +17,20 @@ import java.util.function.Consumer;
*/ */
public abstract class AbstractStateMachine<S> extends AbstractStateManager<S> implements StateMachine<S> { public abstract class AbstractStateMachine<S> extends AbstractStateManager<S> implements StateMachine<S> {
/**
* 状态机上下文
*/
protected final StateMachineContext<S> context; protected final StateMachineContext<S> context;
/** /**
* 默认的构造函数 * 默认的构造函数
* *
* @param entryHandlers 进入事件处理器集合 * @param stateList 状态列表
* @param leaveHandlers 离开事件处理器集合 * @param context 状态机上下文
* @param exchangeHandlers 交换事件处理器集合
* @param executor 异步执行器
* @param async 是否异步执行
*/ */
AbstractStateMachine(List<S> stateList, public AbstractStateMachine(List<S> stateList, StateMachineContext<S> context) {
Map<S, List<StateHandlerWrapper<S>>> entryHandlers,
Map<S, List<StateHandlerWrapper<S>>> leaveHandlers,
Map<String, List<StateHandlerWrapper<S>>> exchangeHandlers,
Map<Object, List<Consumer<StateMachine<S>>>> eventRegistries,
Executor executor,
Boolean async
) {
super(stateList); super(stateList);
context = new StateMachineContext<>(entryHandlers, leaveHandlers, exchangeHandlers, eventRegistries, executor, async); this.context = context;
} }
@Override @Override
@@ -52,6 +42,9 @@ public abstract class AbstractStateMachine<S> extends AbstractStateManager<S> im
if (executor instanceof ExecutorService) { if (executor instanceof ExecutorService) {
ExecutorService es = (ExecutorService) executor; ExecutorService es = (ExecutorService) executor;
es.shutdown(); es.shutdown();
if (!es.awaitTermination(10, TimeUnit.SECONDS)) {
es.shutdownNow();
}
} else if (executor instanceof AutoCloseable) { } else if (executor instanceof AutoCloseable) {
AutoCloseable ac = (AutoCloseable) executor; AutoCloseable ac = (AutoCloseable) executor;
ac.close(); ac.close();
@@ -188,9 +181,19 @@ public abstract class AbstractStateMachine<S> extends AbstractStateManager<S> im
@Override @Override
public void publish(Object event) { public void publish(Object event) {
List<Consumer<StateMachine<S>>> consumers = context.eventRegistries.get(event); List<Consumer<StateMachine<S>>> consumers = context.eventRegistries.get(event);
if (consumers != null) { if (consumers == null ||
consumers.forEach(consumer -> consumer.accept(this)); consumers.isEmpty()) {
return;
} }
final Executor executor = context.executor;
final boolean async = context.async != null && context.async && executor != null;
consumers.forEach(consumer -> {
if (async)
executor.execute(() -> consumer.accept(this));
else
consumer.accept(this);
});
} }
@Override @Override
@@ -241,38 +244,13 @@ public abstract class AbstractStateMachine<S> extends AbstractStateManager<S> im
*/ */
protected final void invokeHandlers(S from, S to) { protected final void invokeHandlers(S from, S to) {
// 触发离开处理器 // 触发离开处理器
doInvokeHandlers(context.leaveHandlers.get(from), from, to); HandlerInvocationDelegate.doInvokeHandlers(context, context.leaveHandlers.get(from), from, to);
// 触发进入处理器 // 触发进入处理器
doInvokeHandlers(context.entryHandlers.get(to), from, to); HandlerInvocationDelegate.doInvokeHandlers(context, context.entryHandlers.get(to), from, to);
// 触发交换处理器 // 触发交换处理器
final String key = from.toString() + "-" + to.toString(); final String key = from.toString() + "-" + to.toString();
doInvokeHandlers(context.exchangeHandlers.get(key), from, to); HandlerInvocationDelegate.doInvokeHandlers(context, context.exchangeHandlers.get(key), from, to);
}
/**
* 触发
*/
private void doInvokeHandlers(List<StateHandlerWrapper<S>> handlerWrappers, S from, S to) {
if (handlerWrappers == null)
return;
handlerWrappers.forEach(hw -> {
final StateHandler<S> stateHandler;
if (hw == null ||
(stateHandler = hw.getStateHandler()) == null)
return;
final StateHandlerProcessParams<S> params = new StateHandlerProcessParams<>(from, to, null);
if (hw.getAsync() == null ?
(context.async != null && context.async) :
hw.getAsync()) {
final Executor executor;
if ((executor = hw.getExecutor() == null ?
context.executor : hw.getExecutor()) == null)
throw new NullPointerException();
executor.execute(() -> stateHandler.handle(params));
} else
stateHandler.handle(params);
});
} }
} }

View File

@@ -1,8 +1,9 @@
package com.serliunx.statemanagement.machine; package com.serliunx.statemanagement.machine;
/** /**
* 基本行为与{@link StateMachine} 一致, 最大不同是切换状态不再使用直接的锁机制, 具体由实现类决定 * 基本行为与{@link StateMachine} 一致, 最大不同是切换状态不再使用直接的锁机制, 具体由实现类决定;
* <li> 默认实现{@link DefaultConcurrentStateMachine}, 状态切换序列由CAS实现. * <p>
* 默认实现{@link DefaultConcurrentStateMachine}, 状态切换序列由CAS实现.
* *
* @author <a href="mailto:serliunx@yeah.net">SerLiunx</a> * @author <a href="mailto:serliunx@yeah.net">SerLiunx</a>
* @version 1.0.0 * @version 1.0.0
@@ -12,8 +13,7 @@ package com.serliunx.statemanagement.machine;
public interface ConcurrentStateMachine<S> extends StateMachine<S> { public interface ConcurrentStateMachine<S> extends StateMachine<S> {
/** /**
* 尝试使用CAS更新状态 * 尝试使用CAS更新状态, 成功更新时触发状态处理器
* <li> 无论是否成功更新都不触发状态处理器
* *
* @param expectedValue 前置状态 * @param expectedValue 前置状态
* @param newValue 更新的状态值 * @param newValue 更新的状态值

View File

@@ -28,13 +28,20 @@ public class DefaultConcurrentStateMachine<S> extends AbstractStateMachine<S> im
Map<String, List<StateHandlerWrapper<S>>> exchangeHandlers, Map<String, List<StateHandlerWrapper<S>>> exchangeHandlers,
Map<Object, List<Consumer<StateMachine<S>>>> eventRegistries, Map<Object, List<Consumer<StateMachine<S>>>> eventRegistries,
Executor executor, Executor executor,
Boolean async) { Boolean async,
super(stateList, entryHandlers, leaveHandlers, exchangeHandlers, eventRegistries, executor, async); S initialState
) {
super(stateList, new StateMachineContext<>(entryHandlers, leaveHandlers, exchangeHandlers, eventRegistries, executor, async, initialState));
final int initialIndex = indexOf(context.initialState);
if (initialIndex != -1) {
updateCurrentIndex(initialIndex);
}
} }
@Override @Override
public boolean compareAndSet(S expectedValue, S newValue) { public boolean compareAndSet(S expectedValue, S newValue) {
return compareAndSet(expectedValue, newValue, false); return compareAndSet(expectedValue, newValue, true);
} }
@Override @Override
@@ -44,10 +51,10 @@ public class DefaultConcurrentStateMachine<S> extends AbstractStateMachine<S> im
if (current == -1 || newIndex == -1) if (current == -1 || newIndex == -1)
return false; return false;
S oldState = get(index.get()); S oldState = get(current);
boolean result = index.compareAndSet(current, newIndex); boolean result = index.compareAndSet(current, newIndex);
if (result && invokeHandlers) { if (result && invokeHandlers) {
S newState = get(index.get()); S newState = get(newIndex);
invokeHandlers(oldState, newState); invokeHandlers(oldState, newState);
} }
@@ -147,8 +154,15 @@ public class DefaultConcurrentStateMachine<S> extends AbstractStateMachine<S> im
return get(index.get()); return get(index.get());
} }
@Override
protected void updateCurrentIndex(int newIndex) {
this.index.set(newIndex);
}
/** /**
* 是否为默认状态 * 是否为默认状态
*
* @return 默认状态时返回真, 否则返回假.
*/ */
protected boolean isDefault() { protected boolean isDefault() {
return index.get() == 0; return index.get() == 0;
@@ -156,7 +170,9 @@ public class DefaultConcurrentStateMachine<S> extends AbstractStateMachine<S> im
/** /**
* 移动下标至上一个状态 * 移动下标至上一个状态
* <li> 使用CAS一直尝试, 直到成功 * <p>
* 使用CAS一直尝试, 直到成功
* </p>
*/ */
protected void exchangeToPrev() { protected void exchangeToPrev() {
final int size = size(); final int size = size();
@@ -168,7 +184,9 @@ public class DefaultConcurrentStateMachine<S> extends AbstractStateMachine<S> im
/** /**
* 移动下标至下一个状态 * 移动下标至下一个状态
* <li> 使用CAS一直尝试, 直到成功 * <p>
* 使用CAS一直尝试, 直到成功
* </p>
*/ */
protected void exchangeToNext() { protected void exchangeToNext() {
final int size = size(); final int size = size();
@@ -180,7 +198,9 @@ public class DefaultConcurrentStateMachine<S> extends AbstractStateMachine<S> im
/** /**
* 切换到指定状态值 * 切换到指定状态值
* <li> 使用CAS一直尝试, 直到成功 * <p>
* 使用CAS一直尝试, 直到成功
* </p>
* *
* @param target 目标值 * @param target 目标值
*/ */

View File

@@ -0,0 +1,80 @@
package com.serliunx.statemanagement.machine;
import com.serliunx.statemanagement.machine.handler.StateHandler;
import com.serliunx.statemanagement.machine.handler.StateHandlerProcessParams;
import com.serliunx.statemanagement.machine.handler.StateHandlerWrapper;
import java.util.List;
import java.util.concurrent.Executor;
/**
* 状态处理器触发
*
* @author <a href="mailto:serliunx@yeah.net">SerLiunx</a>
* @since 2025/3/28
*/
public final class HandlerInvocationDelegate {
/**
* 触发处理器
*
* @param context 状态机上下文
* @param from 源状态
* @param to 目的状态
* @param <S> 状态类型
*/
public static <S> void invokeHandlers(StateMachineContext<S> context, S from, S to) {
// 触发离开处理器
doInvokeHandlers(context, context.leaveHandlers.get(from), from, to);
// 触发进入处理器
doInvokeHandlers(context, context.entryHandlers.get(to), from, to);
// 触发交换处理器
final String key = from.toString() + "-" + to.toString();
doInvokeHandlers(context, context.exchangeHandlers.get(key), from, to);
}
/**
* 触发逻辑
*
* @param context 状态机上下文
* @param handlerWrappers 封装后处理器集合
* @param from 源状态
* @param to 目的状态
* @param <S> 状态类型
*/
public static <S> void doInvokeHandlers(StateMachineContext<S> context,
List<StateHandlerWrapper<S>> handlerWrappers, S from, S to) {
if (handlerWrappers == null)
return;
handlerWrappers.forEach(hw -> {
final StateHandler<S> stateHandler;
if (hw == null ||
(stateHandler = hw.getStateHandler()) == null)
return;
final StateHandlerProcessParams<S> params = new StateHandlerProcessParams<>(from, to, null);
/*
* 一、异步逻辑校验: 首先判断是否需要异步执行状态处理器, 具体的状态逻辑处理器优先级大于全局
* 即: 如果全局指定了同步执行, 但此时特定的状态处理器注册时指定为异步执行的话. 该处理器
* 为异步执行.
*
* 二、 当确定了为异步执行时会选择合适的异步执行器(通常都是线程池), 如果状态处理器注册
* 时指定了异步执行器, 则优先使用该异步执行器;反则会使用全局的异步执行器。如果上一步骤
* 中确定为异步执行但当前步骤没有寻找到合适的异步执行器则会报空指针异常(当前版本不会出现)
*/
if (hw.getAsync() == null ?
(context.async != null && context.async) :
hw.getAsync()) {
final Executor executor;
if ((executor = hw.getExecutor() == null ?
context.executor : hw.getExecutor()) == null)
// 不应该发生
throw new Error();
executor.execute(() -> stateHandler.handle(params));
} else
stateHandler.handle(params);
});
}
}

View File

@@ -31,8 +31,15 @@ public class StandardStateMachine<S> extends AbstractStateMachine<S> implements
Map<String, List<StateHandlerWrapper<S>>> exchangeHandlers, Map<String, List<StateHandlerWrapper<S>>> exchangeHandlers,
Map<Object, List<Consumer<StateMachine<S>>>> eventRegistries, Map<Object, List<Consumer<StateMachine<S>>>> eventRegistries,
Executor executor, Executor executor,
Boolean async Boolean async,
S initialState
) { ) {
super(stateList, entryHandlers, leaveHandlers, exchangeHandlers, eventRegistries, executor, async); super(stateList, new StateMachineContext<>(entryHandlers, leaveHandlers, exchangeHandlers, eventRegistries,
executor, async, initialState));
final int initialIndex = indexOf(context.initialState);
if (initialIndex != -1) {
updateCurrentIndex(initialIndex);
}
} }
} }

View File

@@ -0,0 +1,140 @@
package com.serliunx.statemanagement.machine;
import com.serliunx.statemanagement.machine.external.FlexibleStateMachine;
import com.serliunx.statemanagement.machine.handler.StateHandler;
import java.util.concurrent.Executor;
/**
* 状态机之状态事件注册
* <p>
* 注册状态切换时的事件, 一般用于状态机构建和支持动态调整的状态机{@link FlexibleStateMachine};
* 当然实际不仅于此, 任何相关的都可以使用.
* </p>
*
* @author <a href="mailto:serliunx@yeah.net">SerLiunx</a>
* @since 2025/3/28
* @see FlexibleStateMachine
*/
public interface StateEventRegistry<S> {
/**
* 添加进入事件
* <p>
* 切换到了指定状态时执行的逻辑
* </p>
*
* @param state 状态
* @param handler 处理逻辑
* @param async 是否异步执行
* @param executor 异步执行器, 异步执行时将使用, 不指定时将使用状态机内置的执行器
* @return 当前对象, 链式调用
*/
StateEventRegistry<S> whenEntry(S state, StateHandler<S> handler, Boolean async, Executor executor);
/**
* 添加进入事件
* <p>
* 切换到了指定状态时执行的逻辑
* </p>
*
* @param state 状态
* @param handler 处理逻辑
* @param async 是否异步执行
* @return 当前对象, 链式调用
*/
StateEventRegistry<S> whenEntry(S state, StateHandler<S> handler, Boolean async);
/**
* 添加进入事件
* <p>
* 切换到了指定状态时执行的逻辑
* </p>
*
* @param state 状态
* @param handler 处理逻辑
* @return 当前对象, 链式调用
*/
StateEventRegistry<S> whenEntry(S state, StateHandler<S> handler);
/**
* 添加离开事件
* <p>
* 从指定状态切换到别的状态时执行的逻辑
* </p>
*
* @param state 状态
* @param handler 处理逻辑
* @param async 是否异步执行
* @param executor 异步执行器, 异步执行时将使用, 不指定时将使用状态机内置的执行器
* @return 当前对象, 链式调用
*/
StateEventRegistry<S> whenLeave(S state, StateHandler<S> handler, Boolean async, Executor executor);
/**
* 添加离开事件
* <p>
* 从指定状态切换到别的状态时执行的逻辑
* </p>
*
* @param state 状态
* @param handler 处理逻辑
* @param async 是否异步执行
* @return 当前对象, 链式调用
*/
StateEventRegistry<S> whenLeave(S state, StateHandler<S> handler, Boolean async);
/**
* 添加离开事件
* <p>
* 从指定状态切换到别的状态时执行的逻辑
* </p>
*
* @param state 状态
* @param handler 处理逻辑
* @return 当前对象, 链式调用
*/
StateEventRegistry<S> whenLeave(S state, StateHandler<S> handler);
/**
* 添加交换事件
* <p>
* 从A状态切换至B状态时触发
* </p>
*
* @param from 源状态
* @param to 目的状态
* @param handler 处理器
* @param async 是否异步执行
* @param executor 异步执行器, 异步执行时将使用, 不指定时将使用状态机内置的执行器
* @return 当前对象, 链式调用
*/
StateEventRegistry<S> exchange(S from, S to, StateHandler<S> handler, Boolean async, Executor executor);
/**
* 添加交换事件
* <p>
* 从A状态切换至B状态时触发
* </p>
*
* @param from 源状态
* @param to 目的状态
* @param handler 处理器
* @param async 是否异步执行
* @return 当前对象, 链式调用
*/
StateEventRegistry<S> exchange(S from, S to, StateHandler<S> handler, Boolean async);
/**
* 添加交换事件
* <p>
* 从A状态切换至B状态时触发
* </p>
*
* @param from 源状态
* @param to 目的状态
* @param handler 处理器
* @return 当前对象, 链式调用
*/
StateEventRegistry<S> exchange(S from, S to, StateHandler<S> handler);
}

View File

@@ -5,11 +5,13 @@ import com.serliunx.statemanagement.manager.BidirectionalStateManager;
/** /**
* 状态机定义 * 状态机定义
* <p> * <p>
* 基于双向的状态管理器扩展 {@link BidirectionalStateManager}, 切换逻辑依赖于内置的状态管理器; * 基于双向的状态管理器扩展 {@link BidirectionalStateManager};
* 同时可以多种监听事件, 包括: * 同时可以监听多种事件和发布事件, 包括:
* <ul>
* <li> 切换至指定状态时触发 (进入事件) * <li> 切换至指定状态时触发 (进入事件)
* <li> 切出指定状态时触发 (离开事件) * <li> 切出指定状态时触发 (离开事件)
* <li> 从A切换到B状态时触发 (交换事件) * <li> 从A切换到B状态时触发 (交换事件)
* </ul>
* <p> * <p>
* 请使用 {@link StateMachineBuilder} 来构建状态机. * 请使用 {@link StateMachineBuilder} 来构建状态机.
* *
@@ -77,7 +79,9 @@ public interface StateMachine<S> extends BidirectionalStateManager<S>, AutoClose
/** /**
* 切换至指定状态 * 切换至指定状态
* <li> 在使用状态机的情况, 仅切换成功才会触发注册的各种事件. * <p>
* 在使用状态机的情况, 仅切换成功才会触发注册的各种事件.
* </p>
* *
* @param invokeHandlers 是否唤醒状态处理器 * @param invokeHandlers 是否唤醒状态处理器
* @param state 新的状态 * @param state 新的状态
@@ -94,7 +98,9 @@ public interface StateMachine<S> extends BidirectionalStateManager<S>, AutoClose
/** /**
* 切换至指定状态 * 切换至指定状态
* <li> 在使用状态机的情况, 仅切换成功才会触发注册的各种事件. * <p>
* 在使用状态机的情况, 仅切换成功才会触发注册的各种事件.
* </p>
* *
* @param state 新的状态 * @param state 新的状态
* @return 切换成功返回真, 否则返回假 * @return 切换成功返回真, 否则返回假

View File

@@ -14,7 +14,7 @@ import java.util.function.Consumer;
* @version 1.0.0 * @version 1.0.0
* @since 2024/12/28 * @since 2024/12/28
*/ */
public final class StateMachineBuilder<S> { public final class StateMachineBuilder<S> implements StateEventRegistry<S> {
/** /**
* 状态管理器 * 状态管理器
@@ -32,6 +32,10 @@ public final class StateMachineBuilder<S> {
* 状态机类型 * 状态机类型
*/ */
private StateMachineType type = StateMachineType.STANDARD; private StateMachineType type = StateMachineType.STANDARD;
/**
* 初始化状态
*/
private S initialState;
/** /**
* 各种事件 * 各种事件
@@ -49,17 +53,18 @@ public final class StateMachineBuilder<S> {
this(Arrays.asList(states)); this(Arrays.asList(states));
} }
/** /**
* 添加交换事件 * 定义初始状态
* <li> 从A状态切换至B状态时触发
* *
* @param from 源状态 * @param initialState 初始状态
* @param to 目的状态 * @return 状态机构建
* @param handler 处理器
* @param async 是否异步执行
* @param executor 异步执行器, 异步执行时将使用, 不指定时将使用状态机内置的执行器
*/ */
public StateMachineBuilder<S> withInitial(S initialState) {
this.initialState = initialState;
return this;
}
@Override
public StateMachineBuilder<S> exchange(S from, S to, StateHandler<S> handler, Boolean async, Executor executor) { public StateMachineBuilder<S> exchange(S from, S to, StateHandler<S> handler, Boolean async, Executor executor) {
final String key = from.toString() + "-" + to.toString(); final String key = from.toString() + "-" + to.toString();
final List<StateHandlerWrapper<S>> stateHandlerWrappers = exchangeHandlers.computeIfAbsent(key, final List<StateHandlerWrapper<S>> stateHandlerWrappers = exchangeHandlers.computeIfAbsent(key,
@@ -68,40 +73,17 @@ public final class StateMachineBuilder<S> {
return this; return this;
} }
/** @Override
* 添加交换事件
* <li> 从A状态切换至B状态时触发
*
* @param from 源状态
* @param to 目的状态
* @param handler 处理器
* @param async 是否异步执行
*/
public StateMachineBuilder<S> exchange(S from, S to, StateHandler<S> handler, Boolean async) { public StateMachineBuilder<S> exchange(S from, S to, StateHandler<S> handler, Boolean async) {
return exchange(from, to, handler, async, null); return exchange(from, to, handler, async, null);
} }
/** @Override
* 添加交换事件
* <li> 从A状态切换至B状态时触发
*
* @param from 源状态
* @param to 目的状态
* @param handler 处理器
*/
public StateMachineBuilder<S> exchange(S from, S to, StateHandler<S> handler) { public StateMachineBuilder<S> exchange(S from, S to, StateHandler<S> handler) {
return exchange(from, to, handler, null); return exchange(from, to, handler, null);
} }
/** @Override
* 添加离开事件
* <li> 从指定状态切换到别的状态时执行的逻辑
*
* @param state 状态
* @param handler 处理逻辑
* @param async 是否异步执行
* @param executor 异步执行器, 异步执行时将使用, 不指定时将使用状态机内置的执行器
*/
public StateMachineBuilder<S> whenLeave(S state, StateHandler<S> handler, Boolean async, Executor executor) { public StateMachineBuilder<S> whenLeave(S state, StateHandler<S> handler, Boolean async, Executor executor) {
final List<StateHandlerWrapper<S>> stateHandlerWrappers = leaveHandlers.computeIfAbsent(state, final List<StateHandlerWrapper<S>> stateHandlerWrappers = leaveHandlers.computeIfAbsent(state,
k -> new ArrayList<>()); k -> new ArrayList<>());
@@ -109,38 +91,17 @@ public final class StateMachineBuilder<S> {
return this; return this;
} }
/** @Override
* 添加离开事件
* <li> 从指定状态切换到别的状态时执行的逻辑
*
* @param state 状态
* @param handler 处理逻辑
* @param async 是否异步执行
*/
public StateMachineBuilder<S> whenLeave(S state, StateHandler<S> handler, Boolean async) { public StateMachineBuilder<S> whenLeave(S state, StateHandler<S> handler, Boolean async) {
return whenLeave(state, handler, async, null); return whenLeave(state, handler, async, null);
} }
/** @Override
* 添加离开事件
* <li> 从指定状态切换到别的状态时执行的逻辑
*
* @param state 状态
* @param handler 处理逻辑
*/
public StateMachineBuilder<S> whenLeave(S state, StateHandler<S> handler) { public StateMachineBuilder<S> whenLeave(S state, StateHandler<S> handler) {
return whenLeave(state, handler, null); return whenLeave(state, handler, null);
} }
/** @Override
* 添加进入事件
* <li> 切换到了指定状态时执行的逻辑
*
* @param state 状态
* @param handler 处理逻辑
* @param async 是否异步执行
* @param executor 异步执行器, 异步执行时将使用, 不指定时将使用状态机内置的执行器
*/
public StateMachineBuilder<S> whenEntry(S state, StateHandler<S> handler, Boolean async, Executor executor) { public StateMachineBuilder<S> whenEntry(S state, StateHandler<S> handler, Boolean async, Executor executor) {
final List<StateHandlerWrapper<S>> stateHandlerWrappers = entryHandlers.computeIfAbsent(state, final List<StateHandlerWrapper<S>> stateHandlerWrappers = entryHandlers.computeIfAbsent(state,
k -> new ArrayList<>()); k -> new ArrayList<>());
@@ -148,25 +109,12 @@ public final class StateMachineBuilder<S> {
return this; return this;
} }
/** @Override
* 添加进入事件
* <li> 切换到了指定状态时执行的逻辑
*
* @param state 状态
* @param handler 处理逻辑
* @param async 是否异步执行
*/
public StateMachineBuilder<S> whenEntry(S state, StateHandler<S> handler, Boolean async) { public StateMachineBuilder<S> whenEntry(S state, StateHandler<S> handler, Boolean async) {
return whenEntry(state, handler, async, null); return whenEntry(state, handler, async, null);
} }
/** @Override
* 添加进入事件
* <li> 切换到了指定状态时执行的逻辑
*
* @param state 状态
* @param handler 处理逻辑
*/
public StateMachineBuilder<S> whenEntry(S state, StateHandler<S> handler) { public StateMachineBuilder<S> whenEntry(S state, StateHandler<S> handler) {
return whenEntry(state, handler, null); return whenEntry(state, handler, null);
} }
@@ -176,6 +124,7 @@ public final class StateMachineBuilder<S> {
* *
* @param event 事件 * @param event 事件
* @param logic 切换逻辑 * @param logic 切换逻辑
* @return 当前对象, 链式调用
*/ */
public StateMachineBuilder<S> whenHappened(Object event, Consumer<StateMachine<S>> logic) { public StateMachineBuilder<S> whenHappened(Object event, Consumer<StateMachine<S>> logic) {
List<Consumer<StateMachine<S>>> consumers = eventRegistries.computeIfAbsent(event, k -> new ArrayList<>()); List<Consumer<StateMachine<S>>> consumers = eventRegistries.computeIfAbsent(event, k -> new ArrayList<>());
@@ -189,6 +138,7 @@ public final class StateMachineBuilder<S> {
* 优先级低于添加事件时指定的执行器 * 优先级低于添加事件时指定的执行器
* *
* @param executor 执行器 * @param executor 执行器
* @return 当前对象, 链式调用
*/ */
public StateMachineBuilder<S> executor(Executor executor) { public StateMachineBuilder<S> executor(Executor executor) {
this.executor = executor; this.executor = executor;
@@ -199,6 +149,7 @@ public final class StateMachineBuilder<S> {
* 定义状态机是否异步执行 * 定义状态机是否异步执行
* *
* @param async 是否异步执行 * @param async 是否异步执行
* @return 当前对象, 链式调用
*/ */
public StateMachineBuilder<S> async(Boolean async) { public StateMachineBuilder<S> async(Boolean async) {
this.async = async; this.async = async;
@@ -207,6 +158,8 @@ public final class StateMachineBuilder<S> {
/** /**
* 定义状态机为异步执行 * 定义状态机为异步执行
*
* @return 当前对象, 链式调用
*/ */
public StateMachineBuilder<S> async() { public StateMachineBuilder<S> async() {
return async(true); return async(true);
@@ -214,9 +167,12 @@ public final class StateMachineBuilder<S> {
/** /**
* 指定状态机的类型 * 指定状态机的类型
* <li> 状态机并发与否并不影响事件的执行逻辑 * <p>
* 状态机并发与否并不影响事件的执行逻辑
* </p>
* *
* @param type 类型 * @param type 类型
* @return 当前对象, 链式调用
*/ */
public StateMachineBuilder<S> type(StateMachineType type) { public StateMachineBuilder<S> type(StateMachineType type) {
if (type == null) { if (type == null) {
@@ -228,7 +184,11 @@ public final class StateMachineBuilder<S> {
/** /**
* 指定状态机的类型为标准型 * 指定状态机的类型为标准型
* <li> 状态机并发与否并不影响事件的执行逻辑 * <p>
* 状态机并发与否并不影响事件的执行逻辑
* </p>
*
* @return 当前对象, 链式调用
*/ */
public StateMachineBuilder<S> standard() { public StateMachineBuilder<S> standard() {
return type(StateMachineType.STANDARD); return type(StateMachineType.STANDARD);
@@ -236,14 +196,21 @@ public final class StateMachineBuilder<S> {
/** /**
* 指定状态机的类型为并发型 * 指定状态机的类型为并发型
* <li> 状态机并发与否并不影响事件的执行逻辑 * <p>
* 状态机并发与否并不影响事件的执行逻辑
* </p>
*
* @return 当前对象, 链式调用
*/ */
public StateMachineBuilder<S> concurrent() { public StateMachineBuilder<S> concurrent() {
return type(StateMachineType.CONCURRENT); return type(StateMachineType.CONCURRENT);
} }
/** /**
* 构建 * 执行构建
*
* @param <M> 状态机类型
* @return 状态机
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public <M extends StateMachine<S>> M build() { public <M extends StateMachine<S>> M build() {
@@ -252,10 +219,10 @@ public final class StateMachineBuilder<S> {
} }
if (type.equals(StateMachineType.STANDARD)) { if (type.equals(StateMachineType.STANDARD)) {
return (M)new StandardStateMachine<>(stateList, entryHandlers, return (M)new StandardStateMachine<>(stateList, entryHandlers,
leaveHandlers, exchangeHandlers, eventRegistries, executor, async); leaveHandlers, exchangeHandlers, eventRegistries, executor, async, initialState);
} else if (type.equals(StateMachineType.CONCURRENT)) { } else if (type.equals(StateMachineType.CONCURRENT)) {
return (M)new DefaultConcurrentStateMachine<>(stateList, entryHandlers, return (M)new DefaultConcurrentStateMachine<>(stateList, entryHandlers,
leaveHandlers, exchangeHandlers, eventRegistries, executor, async); leaveHandlers, exchangeHandlers, eventRegistries, executor, async, initialState);
} }
throw new IllegalArgumentException("未知的状态机类型: " + type); throw new IllegalArgumentException("未知的状态机类型: " + type);
} }
@@ -263,6 +230,7 @@ public final class StateMachineBuilder<S> {
/** /**
* 状态机构建器 * 状态机构建器
* *
* @param <S> 状态类型
* @param states 状态集合 * @param states 状态集合
* @return 状态机构建器实例 * @return 状态机构建器实例
*/ */
@@ -273,6 +241,7 @@ public final class StateMachineBuilder<S> {
/** /**
* 状态机构建器 * 状态机构建器
* *
* @param <S> 状态类型
* @param states 状态集合 * @param states 状态集合
* @return 状态机构建器实例 * @return 状态机构建器实例
*/ */

View File

@@ -1,58 +1,144 @@
package com.serliunx.statemanagement.machine; package com.serliunx.statemanagement.machine;
import com.serliunx.statemanagement.machine.handler.StateHandler;
import com.serliunx.statemanagement.machine.handler.StateHandlerWrapper; import com.serliunx.statemanagement.machine.handler.StateHandlerWrapper;
import com.serliunx.statemanagement.support.DefaultCountableRejectedExecutionHandler;
import com.serliunx.statemanagement.support.ExecutorUtils;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import java.util.function.Consumer; import java.util.function.Consumer;
/** /**
* 状态机上下文集合, 用于构建参数封装
*
* @author <a href="mailto:serliunx@yeah.net">SerLiunx</a> * @author <a href="mailto:serliunx@yeah.net">SerLiunx</a>
* @version 1.0.0 * @version 1.0.0
* @since 2025/2/2 * @since 2025/2/2
*/ */
public final class StateMachineContext<S> { public final class StateMachineContext<S> implements StateEventRegistry<S> {
/** /**
* 进入事件集合 * 进入事件集合
*/ */
final Map<S, List<StateHandlerWrapper<S>>> entryHandlers; public Map<S, List<StateHandlerWrapper<S>>> entryHandlers;
/** /**
* 离开事件集合 * 离开事件集合
*/ */
final Map<S, List<StateHandlerWrapper<S>>> leaveHandlers; public Map<S, List<StateHandlerWrapper<S>>> leaveHandlers;
/** /**
* 交换事件集合 * 交换事件集合
*/ */
final Map<String, List<StateHandlerWrapper<S>>> exchangeHandlers; public Map<String, List<StateHandlerWrapper<S>>> exchangeHandlers;
/** /**
* 事件注册集合 * 事件注册集合
*/ */
final Map<Object, List<Consumer<StateMachine<S>>>> eventRegistries; public Map<Object, List<Consumer<StateMachine<S>>>> eventRegistries;
/** /**
* 异步执行器 * 异步执行器
*/ */
final Executor executor; public Executor executor;
/** /**
* 是否异步执行 * 是否异步执行
* <p> * <p>
* 当具体的执行器没有指定是否异步时, 将根据该值决定是否异步执行. * 当具体的执行器没有指定是否异步时, 将根据该值决定是否异步执行.
*/ */
final Boolean async; public Boolean async;
/**
* 初始化状态
*/
public S initialState;
StateMachineContext(Map<S, List<StateHandlerWrapper<S>>> entryHandlers, public StateMachineContext(Map<S, List<StateHandlerWrapper<S>>> entryHandlers,
Map<S, List<StateHandlerWrapper<S>>> leaveHandlers,
Map<String, List<StateHandlerWrapper<S>>> exchangeHandlers,
Map<Object, List<Consumer<StateMachine<S>>>> eventRegistries,
Executor executor,
Boolean async,
S initialState
) {
this.entryHandlers = entryHandlers;
this.leaveHandlers = leaveHandlers;
this.exchangeHandlers = exchangeHandlers;
this.executor = executorAutoConfiguration(executor);
this.async = async;
this.eventRegistries = eventRegistries;
this.initialState = initialState;
}
public StateMachineContext(Map<S, List<StateHandlerWrapper<S>>> entryHandlers,
Map<S, List<StateHandlerWrapper<S>>> leaveHandlers, Map<S, List<StateHandlerWrapper<S>>> leaveHandlers,
Map<String, List<StateHandlerWrapper<S>>> exchangeHandlers, Map<String, List<StateHandlerWrapper<S>>> exchangeHandlers,
Map<Object, List<Consumer<StateMachine<S>>>> eventRegistries, Map<Object, List<Consumer<StateMachine<S>>>> eventRegistries,
Executor executor, Executor executor,
Boolean async Boolean async
) { ) {
this.entryHandlers = entryHandlers; this(entryHandlers, leaveHandlers, exchangeHandlers, eventRegistries, executor, async, null);
this.leaveHandlers = leaveHandlers; }
this.exchangeHandlers = exchangeHandlers;
this.executor = executor; @Override
this.async = async; public StateMachineContext<S> whenEntry(S state, StateHandler<S> handler, Boolean async, Executor executor) {
this.eventRegistries = eventRegistries; final List<StateHandlerWrapper<S>> stateHandlerWrappers = entryHandlers.computeIfAbsent(state,
k -> new ArrayList<>());
stateHandlerWrappers.add(new StateHandlerWrapper<>(handler, executor, async));
return this;
}
@Override
public StateMachineContext<S> whenEntry(S state, StateHandler<S> handler, Boolean async) {
return whenEntry(state, handler, async, null);
}
@Override
public StateMachineContext<S> whenEntry(S state, StateHandler<S> handler) {
return whenEntry(state, handler, null);
}
@Override
public StateMachineContext<S> whenLeave(S state, StateHandler<S> handler, Boolean async, Executor executor) {
final List<StateHandlerWrapper<S>> stateHandlerWrappers = leaveHandlers.computeIfAbsent(state,
k -> new ArrayList<>());
stateHandlerWrappers.add(new StateHandlerWrapper<>(handler, executor, async));
return this;
}
@Override
public StateMachineContext<S> whenLeave(S state, StateHandler<S> handler, Boolean async) {
return whenLeave(state, handler, async, null);
}
@Override
public StateMachineContext<S> whenLeave(S state, StateHandler<S> handler) {
return whenLeave(state, handler, null);
}
@Override
public StateMachineContext<S> exchange(S from, S to, StateHandler<S> handler, Boolean async, Executor executor) {
final List<StateHandlerWrapper<S>> stateHandlerWrappers = exchangeHandlers.computeIfAbsent(from.toString()
+ "-" + to.toString(), k -> new ArrayList<>());
stateHandlerWrappers.add(new StateHandlerWrapper<>(handler, executor, async));
return this;
}
@Override
public StateMachineContext<S> exchange(S from, S to, StateHandler<S> handler, Boolean async) {
return exchange(from, to, handler, async, null);
}
@Override
public StateMachineContext<S> exchange(S from, S to, StateHandler<S> handler) {
return exchange(from, to, handler, null);
}
/**
* 执行器为空时自动创建一个适合当前操作系统的执行器(线程池)
*/
private Executor executorAutoConfiguration(Executor source) {
if (source == null) {
return ExecutorUtils.adaptiveThreadPool(new DefaultCountableRejectedExecutionHandler());
}
return source;
} }
} }

View File

@@ -11,6 +11,7 @@ public enum StateMachineType {
* 标准, 切换使用读写锁 * 标准, 切换使用读写锁
*/ */
STANDARD, STANDARD,
/** /**
* 并发型, 切换使用CAS乐观锁 * 并发型, 切换使用CAS乐观锁
*/ */

View File

@@ -0,0 +1,48 @@
package com.serliunx.statemanagement.machine.external;
import com.serliunx.statemanagement.machine.StateEventRegistry;
import com.serliunx.statemanagement.machine.StateMachine;
import com.serliunx.statemanagement.machine.handler.StateHandler;
import com.serliunx.statemanagement.machine.handler.StateHandlerWrapper;
import java.util.List;
/**
* 可变的、灵活的状态机, 支持在运行的过程中动态的增减状态及状态切换的事件
*
* @author <a href="mailto:serliunx@yeah.net">SerLiunx</a>
* @since 2025/3/28
*/
public interface FlexibleStateMachine<S> extends StateMachine<S>, StateEventRegistry<S> {
/**
* 获取指定状态下所有的离开事件处理器.
* <p>
* 通过 {@link StateEventRegistry#whenLeave(Object, StateHandler)} 等方法注册.
*
* @param state 状态
* @return 所有与指定状态相关的离开事件处理器
*/
List<StateHandlerWrapper<S>> allLeaveHandlers(S state);
/**
* 获取指定状态下所有的进入事件处理器.
* <p>
* 通过 {@link StateEventRegistry#whenEntry(Object, StateHandler)} 等方法注册.
*
* @param state 状态
* @return 所有与指定状态相关的进入事件处理器
*/
List<StateHandlerWrapper<S>> allEntryHandlers(S state);
/**
* 获取指定状态下所有的交换事件处理器.
* <p>
* 通过 {@link StateEventRegistry#exchange(Object, Object, StateHandler)} 等方法注册.
*
* @param from 源状态
* @param to 目标状态
* @return 所有与指定状态相关的交换事件处理器
*/
List<StateHandlerWrapper<S>> allExchangeHandlers(S from, S to);
}

View File

@@ -9,7 +9,6 @@ package com.serliunx.statemanagement.machine.handler;
* @version 1.0.0 * @version 1.0.0
* @since 2024/12/28 * @since 2024/12/28
*/ */
@SuppressWarnings("all")
public final class StateHandlerProcessParams<S> { public final class StateHandlerProcessParams<S> {
/** /**
@@ -29,7 +28,6 @@ public final class StateHandlerProcessParams<S> {
* @param from 原状态 * @param from 原状态
* @param to 目标状态 * @param to 目标状态
* @param attach 附加参数 * @param attach 附加参数
* @param bidirectionalStateManager 状态机内置的状态管理器
*/ */
public StateHandlerProcessParams(S from, S to, Object attach) { public StateHandlerProcessParams(S from, S to, Object attach) {
this.from = from; this.from = from;

View File

@@ -1,10 +0,0 @@
package com.serliunx.statemanagement.machine.handler;
/**
* @author <a href="mailto:serliunx@yeah.net">SerLiunx</a>
* @version 1.0.0
* @since 2024/12/28
*/
public class StateHandlerRegistry {
}

View File

@@ -11,7 +11,6 @@ import java.util.concurrent.Executor;
* @version 1.0.0 * @version 1.0.0
* @since 2024/12/28 * @since 2024/12/28
*/ */
@SuppressWarnings("all")
public final class StateHandlerWrapper<S> { public final class StateHandlerWrapper<S> {
/** /**
@@ -20,7 +19,8 @@ public final class StateHandlerWrapper<S> {
private final StateHandler<S> stateHandler; private final StateHandler<S> stateHandler;
/** /**
* 执行器 * 执行器
* <li> 用于异步执行处理逻辑 * <p>
* 用于异步执行处理逻辑
*/ */
private final Executor executor; private final Executor executor;
/** /**

View File

@@ -0,0 +1,94 @@
package com.serliunx.statemanagement.machine.support;
import com.serliunx.statemanagement.machine.ConcurrentStateMachine;
import com.serliunx.statemanagement.machine.StateMachine;
import com.serliunx.statemanagement.machine.StateMachineBuilder;
import java.util.List;
/**
* 状态机工具类集合
*
* @author <a href="mailto:serliunx@yeah.net">SerLiunx</a>
* @since 2025/4/11
*/
public final class StateMachines {
/**
* 获取一个仅包含状态的并发型状态机
* <p>
* 所生成的状态机没有任务事件逻辑,此时仅用作普通的双向状态管理器使用
* </p>
*
* @param states 状态集合
*
* @return 仅包含状态的并发型状态机
* @param <S> 状态
* @see ConcurrentStateMachine
* @see com.serliunx.statemanagement.manager.BidirectionalStateManager
*/
public static <S> ConcurrentStateMachine<S> concurrentStateMachine(S[] states) {
return StateMachineBuilder.from(states)
.async(false)
.concurrent()
.build();
}
/**
* 获取一个仅包含状态的并发型状态机
* <p>
* 所生成的状态机没有任务事件逻辑,此时仅用作普通的双向状态管理器使用
* </p>
*
* @param states 状态集合
*
* @return 仅包含状态的并发型状态机
* @param <S> 状态
* @see ConcurrentStateMachine
* @see com.serliunx.statemanagement.manager.BidirectionalStateManager
*/
public static <S> ConcurrentStateMachine<S> concurrentStateMachine(List<S> states) {
return StateMachineBuilder.from(states)
.async(false)
.concurrent()
.build();
}
/**
* 获取一个仅包含状态的普通状态机
* <p>
* 所生成的状态机没有任务事件逻辑,此时仅用作普通的双向状态管理器使用
* </p>
*
* @param states 状态集合
*
* @return 仅包含状态的普通状态机
* @param <S> 状态
* @see StateMachine
* @see com.serliunx.statemanagement.manager.BidirectionalStateManager
*/
public static <S> StateMachine<S> defaultStateMachine(S[] states) {
return StateMachineBuilder.from(states)
.async(false)
.build();
}
/**
* 获取一个仅包含状态的普通状态机
* <p>
* 所生成的状态机没有任务事件逻辑,此时仅用作普通的双向状态管理器使用
* </p>
*
* @param states 状态集合
*
* @return 仅包含状态的普通状态机
* @param <S> 状态
* @see StateMachine
* @see com.serliunx.statemanagement.manager.BidirectionalStateManager
*/
public static <S> StateMachine<S> defaultStateMachine(List<S> states) {
return StateMachineBuilder.from(states)
.async(false)
.build();
}
}

View File

@@ -26,6 +26,11 @@ public abstract class AbstractStateManager<S> implements StateManager<S> {
*/ */
private volatile int index; private volatile int index;
/**
* 默认状态序号
*/
private int defaultIndex = 0;
/** /**
* 锁 * 锁
*/ */
@@ -105,15 +110,12 @@ public abstract class AbstractStateManager<S> implements StateManager<S> {
return stateList.size(); return stateList.size();
} }
@Override
public boolean isSwitchable() {
return stateList.size() > 1;
}
/** /**
* 将序号移动至下一个 * 将序号移动至下一个
* <ul>
* <li> 自动归零 * <li> 自动归零
* <li> 仅在持有写锁的情况下访问 * <li> 仅在持有写锁的情况下访问
* </ul>
*/ */
@SuppressWarnings("all") @SuppressWarnings("all")
protected void next() { protected void next() {
@@ -123,13 +125,15 @@ public abstract class AbstractStateManager<S> implements StateManager<S> {
/** /**
* 将序号移动至上一个 * 将序号移动至上一个
* <ul>
* <li> 自动归零 * <li> 自动归零
* <li> 仅在持有写锁的情况下访问 * <li> 仅在持有写锁的情况下访问
* </ul>
*/ */
@SuppressWarnings("all") @SuppressWarnings("all")
protected void prev() { protected void prev() {
if (--index < 0) if (--index < 0)
index = 0; index = stateList.size() - 1;
} }
/** /**
@@ -137,7 +141,9 @@ public abstract class AbstractStateManager<S> implements StateManager<S> {
* <p> * <p>
* 类及子类访问当前状态时不允许使用{@link #current()},因为会造成死锁 * 类及子类访问当前状态时不允许使用{@link #current()},因为会造成死锁
* *
* <li> 仅在持有锁的情况下访问 * <p>
* 仅在持有锁的情况下访问
* </p>
* *
* @return 当前状态 * @return 当前状态
*/ */
@@ -162,6 +168,9 @@ public abstract class AbstractStateManager<S> implements StateManager<S> {
* @return 序号 {@link List#indexOf(Object)} * @return 序号 {@link List#indexOf(Object)}
*/ */
protected int indexOf(S state) { protected int indexOf(S state) {
if (state == null) {
return -1;
}
return stateList.indexOf(state); return stateList.indexOf(state);
} }
@@ -180,7 +189,7 @@ public abstract class AbstractStateManager<S> implements StateManager<S> {
* @return 是第一个时返回真, 否则返回假. * @return 是第一个时返回真, 否则返回假.
*/ */
protected boolean isFirst() { protected boolean isFirst() {
return index == getDefault(); return index == 0;
} }
/** /**
@@ -194,6 +203,8 @@ public abstract class AbstractStateManager<S> implements StateManager<S> {
/** /**
* 更新当前状态的序号 * 更新当前状态的序号
*
* @param newIndex 新的序号
*/ */
protected void updateCurrentIndex(int newIndex) { protected void updateCurrentIndex(int newIndex) {
index = newIndex; index = newIndex;
@@ -201,8 +212,19 @@ public abstract class AbstractStateManager<S> implements StateManager<S> {
/** /**
* 状态序号默认值(等同于默认状态) * 状态序号默认值(等同于默认状态)
*
* @return 默认的状态值
*/ */
protected int getDefault() { protected int getDefault() {
return 0; return defaultIndex;
}
/**
* 设置默认值
*
* @param defaultIndex 默认值
*/
protected void setDefault(int defaultIndex) {
this.defaultIndex = defaultIndex;
} }
} }

View File

@@ -6,8 +6,10 @@ import java.util.List;
/** /**
* 断路的单向状态管理器 * 断路的单向状态管理器
* <p> 逻辑与{@link UnidirectionalStateManager}大体相同, 不同的点在于: * <p>
* <li> 最后一个状态无法转向第一个状态, 即为一次性的状态管理器. * 逻辑与{@link UnidirectionalStateManager}大体相同, 不同的点在于:
* 最后一个状态无法转向第一个状态, 即为一次性的状态管理器.
* </p>
* *
* @author <a href="mailto:serliunx@yeah.net">SerLiunx</a> * @author <a href="mailto:serliunx@yeah.net">SerLiunx</a>
* @version 1.0.0 * @version 1.0.0

View File

@@ -2,7 +2,9 @@ package com.serliunx.statemanagement.manager;
/** /**
* 将指定状态管理器标记为循环的状态管理器 * 将指定状态管理器标记为循环的状态管理器
* <li> 允许单向、双向循环 * <p>
* 允许单向、双向循环
* </p>
* *
* @author <a href="mailto:serliunx@yeah.net">SerLiunx</a> * @author <a href="mailto:serliunx@yeah.net">SerLiunx</a>
* @version 1.0.0 * @version 1.0.0

View File

@@ -83,6 +83,9 @@ public class DefaultUnidirectionalStateManager<S> extends AbstractStateManager<S
/** /**
* 保留默认的切换方式供子类使用 * 保留默认的切换方式供子类使用
*
* @param state 目标状态值
* @return 成功切换返回真, 否则返回假
*/ */
protected boolean defaultSwitchTo(S state) { protected boolean defaultSwitchTo(S state) {
return super.switchTo(state); return super.switchTo(state);

View File

@@ -33,16 +33,60 @@ public interface StateManager<S> {
/** /**
* 获取当前状态数量 * 获取当前状态数量
*
* @return 数量 * @return 数量
*/ */
int size(); int size();
/** /**
* 是否可切换 * 是否可切换
* <p>
* 默认情况下, 状态集合中的状态数量大于1时就可以切换。部分实现在特定情况下可能不允许切换,
* 比如断路的单向状态管理器 {@link BreakageUnidirectionalStateManager}, 当状态为最后一个时
* 则不允许向前、或者向后切换
* </p>
* *
* @return 可切换返回真, 否则返回假 * @return 可切换返回真, 否则返回假
*/ */
default boolean isSwitchable() { default boolean isSwitchable() {
return true; return size() > 1;
}
/**
* 校验当前状态是否为指定的状态
*
* @param state 指定的状态
* @return 符合返回真, 否则返回假
*/
default boolean is(S state) {
return current().equals(state);
}
/**
* 如果是指定的状态则切换到另一个状态
* <p>
* 例: 检测当前状态是否为 1 且可切换, 如何为 1 则将状态切换到 2;
* 结合了 {@link #current()}、 {@link #switchTo(Object)} 及 {@link #isSwitchable()}
* </p>
*
* @param now 当前状态
* @param newState 新的状态
* @return 如果当前状态不符合或者不可切换则返回假, 否则走切换逻辑, 此时结果取决于切换的结果.
*/
default boolean switchToIfMatch(S now, S newState) {
if (isSwitchable() && now.equals(current()))
return switchTo(newState);
return false;
}
/**
* 如果当前状态为指定的状态则运行所指定的逻辑
*
* @param state 状态
* @param action 逻辑
*/
default void computeIfMatch(S state, Runnable action) {
if (is(state))
action.run();
} }
} }

View File

@@ -4,13 +4,13 @@ package com.serliunx.statemanagement.manager;
* 单向流转的状态管理器 * 单向流转的状态管理器
* <p> * <p>
* 其基本逻辑等同于 {@link StateManager}, 但存在以下不同: * 其基本逻辑等同于 {@link StateManager}, 但存在以下不同:
* <li> 状态只能单方向流动(最后一个状态允许切换至第一个状态), 如果有A, B, C, D 四种状态则存在以下几种情况: * 状态只能单方向流动(最后一个状态允许切换至第一个状态), 如果有A, B, C, D 四种状态则存在以下几种情况:
* <p> * </p>
* <p> * <ul>
* <li> A -> B 允许直接切换, A -> C 允许直接切换, C -> D 允许直接切换 等等.. * <li> A B 允许直接切换, A C 允许直接切换, C D 允许直接切换 等等..
* <li> B -> A 不允许切换, C -> A 不允许切换, D -> C 不允许切换 等等.. * <li> B A 不允许切换, C A 不允许切换, D C 不允许切换 等等..
* <li> 特例: D -> A 是允许的, 因为D是最后一个状态, 故可以切换至第一个状态. * <li> 特例: D A 是允许的, 因为 D 是最后一个状态, 故可以切换至第一个状态.
* <p> * </ul>
* 即状态的切换只允许一个方向,不允许向前流动,除非到达最后一个状态! * 即状态的切换只允许一个方向,不允许向前流动,除非到达最后一个状态!
* *
* @author <a href="mailto:serliunx@yeah.net">SerLiunx</a> * @author <a href="mailto:serliunx@yeah.net">SerLiunx</a>

View File

@@ -0,0 +1,27 @@
package com.serliunx.statemanagement.support;
import java.util.concurrent.RejectedExecutionHandler;
/**
* 附带计数的拒绝策略
*
* @author <a href="mailto:serliunx@yeah.net">SerLiunx</a>
* @version 1.0.0
* @since 2025/3/5
*/
public interface CountableRejectedExecutionHandler extends RejectedExecutionHandler {
/**
* 获取当前拒绝的任务数量
*
* @return 当目前为止所拒绝的任务数量
*/
long getCount();
/**
* 获取最后一次被拒绝的任务
*
* @return 最后一次被拒绝的任务
*/
Runnable getLastRejectedTask();
}

View File

@@ -0,0 +1,40 @@
package com.serliunx.statemanagement.support;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.atomic.AtomicLong;
/**
* 附带计数的拒绝策略默认实现(丢弃任务并计数)
*
* @author <a href="mailto:serliunx@yeah.net">SerLiunx</a>
* @version 1.0.0
* @since 2025/3/5
*/
public class DefaultCountableRejectedExecutionHandler implements CountableRejectedExecutionHandler {
/**
* 计数器
*/
private final AtomicLong counter = new AtomicLong(0);
/**
* 最后一次被拒绝的任务
*/
private volatile Runnable last = null;
@Override
public long getCount() {
return counter.get();
}
@Override
public Runnable getLastRejectedTask() {
return last;
}
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
last = r;
counter.incrementAndGet();
}
}

View File

@@ -1,6 +1,10 @@
package com.serliunx.statemanagement.support; package com.serliunx.statemanagement.support;
import java.util.concurrent.*;
/** /**
* 线程池相关工具类
*
* @author <a href="mailto:serliunx@yeah.net">SerLiunx</a> * @author <a href="mailto:serliunx@yeah.net">SerLiunx</a>
* @version 1.0.0 * @version 1.0.0
* @since 2024/12/28 * @since 2024/12/28
@@ -8,4 +12,21 @@ package com.serliunx.statemanagement.support;
public final class ExecutorUtils { public final class ExecutorUtils {
private ExecutorUtils() {throw new UnsupportedOperationException();} private ExecutorUtils() {throw new UnsupportedOperationException();}
/**
* 快速获取自适应参数的线程池
* <p>
* 核心线程数量为当前处理器数量的两倍; 最大线程数量为当前处理器数量的四倍.
* </p>
*
* @param rejectedExecutionHandler 拒绝策略
* @return 执行器(线程池)
*/
public static Executor adaptiveThreadPool(RejectedExecutionHandler rejectedExecutionHandler) {
final int processors = Runtime.getRuntime().availableProcessors();
return new ThreadPoolExecutor(processors * 2, processors * 4, 5,
TimeUnit.MINUTES, new ArrayBlockingQueue<>(processors * 8),
new NamedThreadFactory("state-process-%s"), rejectedExecutionHandler);
}
} }

View File

@@ -0,0 +1,26 @@
package com.serliunx.statemanagement.support;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;
/**
* 模板名称线程池
*
* @author <a href="mailto:serliunx@yeah.net">SerLiunx</a>
* @since 2025/2/17
*/
public final class NamedThreadFactory implements ThreadFactory {
private final AtomicInteger threadNumber = new AtomicInteger(0);
private final String namePattern;
public NamedThreadFactory(String namePattern) {
this.namePattern = namePattern;
}
@Override
public Thread newThread(Runnable r) {
return new Thread(r, String.format(namePattern, threadNumber.getAndIncrement()));
}
}

View File

@@ -5,10 +5,13 @@ import com.serliunx.statemanagement.machine.StateMachine;
import com.serliunx.statemanagement.machine.StateMachineBuilder; import com.serliunx.statemanagement.machine.StateMachineBuilder;
import com.serliunx.statemanagement.support.PrinterEvent; import com.serliunx.statemanagement.support.PrinterEvent;
import com.serliunx.statemanagement.support.PrinterState; import com.serliunx.statemanagement.support.PrinterState;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test; import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
/** /**
* 状态机测试 * 状态机测试
@@ -17,49 +20,58 @@ import java.util.concurrent.Executors;
* @version 1.0.0 * @version 1.0.0
* @since 2024/12/28 * @since 2024/12/28
*/ */
@Slf4j
public class MachineTest { public class MachineTest {
private static final Logger log = LoggerFactory.getLogger(MachineTest.class);
private final ExecutorService executor = Executors.newFixedThreadPool(5);
@Test @Test
public void testStandardStateMachine() throws Exception { public void testStandardStateMachine() throws Exception {
StateMachine<PrinterState> stateMachine = StateMachineBuilder.from(PrinterState.values()) StateMachine<PrinterState> stateMachine = StateMachineBuilder.from(PrinterState.values())
.async(false) .async(true)
.standard() .standard()
.executor(Executors.newFixedThreadPool(16)) .withInitial(PrinterState.STOPPING)
.whenLeave(PrinterState.IDLE, h -> {
System.out.println(Thread.currentThread().getName() + ": leave IDLE");
})
.whenEntry(PrinterState.STOPPING, h -> {
System.out.println(Thread.currentThread().getName() + ": entry STOPPING, from " + h.getFrom());
})
.whenEntry(PrinterState.STOPPED, h -> {
System.out.println(Thread.currentThread().getName() + ": entry STOPPED, from " + h.getFrom());
})
.whenHappened(PrinterEvent.TURN_ON, m -> {
m.switchTo(PrinterState.SCANNING);
})
.whenHappened(PrinterEvent.TURN_OFF, m -> {
if (m.switchTo(PrinterState.STOPPING))
m.switchTo(PrinterState.STOPPED);
})
.build(); .build();
stateMachine.publish(PrinterEvent.TURN_ON); log.info("{}", stateMachine.current());
stateMachine.close();
} }
@Test @Test
public void testConcurrentStateMachine() throws Exception { public void testConcurrentStateMachine() throws Exception {
ConcurrentStateMachine<PrinterState> stateMachine = StateMachineBuilder.from(PrinterState.values()) ConcurrentStateMachine<PrinterState> stateMachine = StateMachineBuilder.from(PrinterState.values())
.async(false)
.whenEntry(PrinterState.STOPPING, h -> { .whenEntry(PrinterState.STOPPING, h -> {
System.out.println(1111); log.info("enter stopping~");
}) })
.whenHappened(PrinterEvent.TURN_OFF, l -> {
if (l.switchTo(PrinterState.STOPPING))
l.switchTo(PrinterState.STOPPED);
})
.withInitial(PrinterState.STOPPING)
.concurrent() .concurrent()
.build(); .build();
System.out.println(stateMachine.compareAndSet(PrinterState.IDLE, PrinterState.STOPPING, true)); log.info("{}", stateMachine.current());
stateMachine.close(); stateMachine.close();
} }
@Test
public void testConcurrentStateMachine2() throws Exception {
ConcurrentStateMachine<PrinterState> stateMachine = StateMachineBuilder.from(PrinterState.values())
.async(false)
.concurrent()
.whenEntry(PrinterState.STOPPING, h -> {
log.info("stopping...");
})
.build();
for (int i = 0; i < 5; i++) {
executor.execute(() -> {
log.info("{}", stateMachine.compareAndSet(PrinterState.IDLE, PrinterState.STOPPING, true));
});
}
TimeUnit.SECONDS.sleep(5);
}
} }

View File

@@ -1,11 +1,10 @@
package com.serliunx.statemanagement; package com.serliunx.statemanagement;
import com.serliunx.statemanagement.manager.BreakageUnidirectionalStateManager; import com.serliunx.statemanagement.manager.*;
import com.serliunx.statemanagement.manager.DefaultUnidirectionalStateManager;
import com.serliunx.statemanagement.manager.UnidirectionalStateManager;
import com.serliunx.statemanagement.support.PrinterState; import com.serliunx.statemanagement.support.PrinterState;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test; import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** /**
* 状态管理器测试 * 状态管理器测试
@@ -14,9 +13,10 @@ import org.junit.Test;
* @version 1.0.0 * @version 1.0.0
* @since 2024/12/28 * @since 2024/12/28
*/ */
@Slf4j
public class ManagerTest { public class ManagerTest {
private static final Logger log = LoggerFactory.getLogger(ManagerTest.class);
@Test @Test
public void testUnidirectionalStateManager() { public void testUnidirectionalStateManager() {
UnidirectionalStateManager<PrinterState> unidirectionalStateManager = UnidirectionalStateManager<PrinterState> unidirectionalStateManager =
@@ -35,4 +35,17 @@ public class ManagerTest {
} }
System.out.println(bum.current()); System.out.println(bum.current());
} }
@Test
public void testDefaultMethod() throws Exception {
BidirectionalStateManager<PrinterState> bsm = new DefaultBidirectionalStateManager<>(PrinterState.values());
bsm.switchPrev();
log.info("{}", bsm.current());
bsm.computeIfMatch(PrinterState.IDLE, () -> {
log.info("hello~");
});
}
} }

View File

@@ -0,0 +1,38 @@
package com.serliunx.statemanagement;
import com.serliunx.statemanagement.machine.ConcurrentStateMachine;
import com.serliunx.statemanagement.machine.StateMachine;
import com.serliunx.statemanagement.machine.support.StateMachines;
import com.serliunx.statemanagement.support.PrinterState;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* 状态机工具类测试
*
* @author <a href="mailto:serliunx@yeah.net">SerLiunx</a>
* @since 2025/4/11
*/
public class StateMachinesTest {
private static final Logger log = LoggerFactory.getLogger(StateMachinesTest.class);
@Test
public void testConcurrentStateMachines() throws Exception {
ConcurrentStateMachine<PrinterState> machine = StateMachines.concurrentStateMachine(PrinterState.values());
log.info("{}", machine.current());
log.info("{}", machine.switchPrevAndGet());
log.info("{}", machine.current());
machine.close();
}
@Test
public void testStateMachines() throws Exception {
StateMachine<PrinterState> machine = StateMachines.defaultStateMachine(PrinterState.values());
log.info("{}", machine.current());
log.info("{}", machine.switchPrevAndGet());
log.info("{}", machine.current());
machine.close();
}
}

View File

@@ -0,0 +1,15 @@
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>
%boldGreen(%d{yyyy-MM-dd HH:mm:ss(SSS)}) %magenta([%25.25thread]) %highlight([%-6level]) %boldCyan(%-36logger{32}): %msg%n
</pattern>
</encoder>
</appender>
<logger name="com.serliunx" level="DEBUG"/>
<root level="DEBUG">
<appender-ref ref="STDOUT" />
</root>
</configuration>