Compare commits
23 Commits
concurrent
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| f733e1ff5a | |||
| c0ccf2cb4f | |||
| cd24c7de99 | |||
| e2a58cf7bd | |||
| 1e9113666b | |||
| d533061410 | |||
| 961a496465 | |||
| 89799257aa | |||
| bbde9acf55 | |||
| cdfe94de08 | |||
| 92ee373ea4 | |||
| 921520b097 | |||
| f0db621968 | |||
| 5d73a20428 | |||
| 974b0ffe6d | |||
| 19ef4f1262 | |||
| f6a3b336de | |||
| 494f093041 | |||
| af9c1c9622 | |||
| f7e4400e37 | |||
| 101d440510 | |||
| 4a843f885e | |||
| 4b4a6d27b3 |
8
pom.xml
8
pom.xml
@@ -22,18 +22,12 @@
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- 日志输出 (仅用于测试) -->
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<version>1.2.13</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.18.36</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -1,6 +1,8 @@
|
||||
package com.serliunx.statemanagement.exception;
|
||||
|
||||
/**
|
||||
* 状态机异常
|
||||
*
|
||||
* @author <a href="mailto:serliunx@yeah.net">SerLiunx</a>
|
||||
* @version 1.0.0
|
||||
* @since 2024/12/28
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
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 java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
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> {
|
||||
|
||||
/**
|
||||
* 状态机上下文
|
||||
*/
|
||||
protected final StateMachineContext<S> context;
|
||||
|
||||
/**
|
||||
* 默认的构造函数
|
||||
*
|
||||
* @param entryHandlers 进入事件处理器集合
|
||||
* @param leaveHandlers 离开事件处理器集合
|
||||
* @param exchangeHandlers 交换事件处理器集合
|
||||
* @param executor 异步执行器
|
||||
* @param async 是否异步执行
|
||||
* @param stateList 状态列表
|
||||
* @param context 状态机上下文
|
||||
*/
|
||||
AbstractStateMachine(List<S> stateList,
|
||||
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
|
||||
) {
|
||||
public AbstractStateMachine(List<S> stateList, StateMachineContext<S> context) {
|
||||
super(stateList);
|
||||
context = new StateMachineContext<>(entryHandlers, leaveHandlers, exchangeHandlers, eventRegistries, executor, async);
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -52,6 +42,9 @@ public abstract class AbstractStateMachine<S> extends AbstractStateManager<S> im
|
||||
if (executor instanceof ExecutorService) {
|
||||
ExecutorService es = (ExecutorService) executor;
|
||||
es.shutdown();
|
||||
if (!es.awaitTermination(10, TimeUnit.SECONDS)) {
|
||||
es.shutdownNow();
|
||||
}
|
||||
} else if (executor instanceof AutoCloseable) {
|
||||
AutoCloseable ac = (AutoCloseable) executor;
|
||||
ac.close();
|
||||
@@ -188,9 +181,19 @@ public abstract class AbstractStateMachine<S> extends AbstractStateManager<S> im
|
||||
@Override
|
||||
public void publish(Object event) {
|
||||
List<Consumer<StateMachine<S>>> consumers = context.eventRegistries.get(event);
|
||||
if (consumers != null) {
|
||||
consumers.forEach(consumer -> consumer.accept(this));
|
||||
if (consumers == null ||
|
||||
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
|
||||
@@ -241,38 +244,13 @@ public abstract class AbstractStateMachine<S> extends AbstractStateManager<S> im
|
||||
*/
|
||||
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();
|
||||
doInvokeHandlers(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);
|
||||
});
|
||||
HandlerInvocationDelegate.doInvokeHandlers(context, context.exchangeHandlers.get(key), from, to);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
package com.serliunx.statemanagement.machine;
|
||||
|
||||
/**
|
||||
* 基本行为与{@link StateMachine} 一致, 最大不同是切换状态不再使用直接的锁机制, 具体由实现类决定
|
||||
* <li> 默认实现{@link DefaultConcurrentStateMachine}, 状态切换序列由CAS实现.
|
||||
* 基本行为与{@link StateMachine} 一致, 最大不同是切换状态不再使用直接的锁机制, 具体由实现类决定;
|
||||
* <p>
|
||||
* 默认实现{@link DefaultConcurrentStateMachine}, 状态切换序列由CAS实现.
|
||||
*
|
||||
* @author <a href="mailto:serliunx@yeah.net">SerLiunx</a>
|
||||
* @version 1.0.0
|
||||
@@ -12,8 +13,7 @@ package com.serliunx.statemanagement.machine;
|
||||
public interface ConcurrentStateMachine<S> extends StateMachine<S> {
|
||||
|
||||
/**
|
||||
* 尝试使用CAS更新状态
|
||||
* <li> 无论是否成功更新都不触发状态处理器
|
||||
* 尝试使用CAS更新状态, 成功更新时触发状态处理器
|
||||
*
|
||||
* @param expectedValue 前置状态
|
||||
* @param newValue 更新的状态值
|
||||
|
||||
@@ -28,13 +28,20 @@ public class DefaultConcurrentStateMachine<S> extends AbstractStateMachine<S> im
|
||||
Map<String, List<StateHandlerWrapper<S>>> exchangeHandlers,
|
||||
Map<Object, List<Consumer<StateMachine<S>>>> eventRegistries,
|
||||
Executor executor,
|
||||
Boolean async) {
|
||||
super(stateList, entryHandlers, leaveHandlers, exchangeHandlers, eventRegistries, executor, async);
|
||||
Boolean 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
|
||||
public boolean compareAndSet(S expectedValue, S newValue) {
|
||||
return compareAndSet(expectedValue, newValue, false);
|
||||
return compareAndSet(expectedValue, newValue, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -44,10 +51,10 @@ public class DefaultConcurrentStateMachine<S> extends AbstractStateMachine<S> im
|
||||
if (current == -1 || newIndex == -1)
|
||||
return false;
|
||||
|
||||
S oldState = get(index.get());
|
||||
S oldState = get(current);
|
||||
boolean result = index.compareAndSet(current, newIndex);
|
||||
if (result && invokeHandlers) {
|
||||
S newState = get(index.get());
|
||||
S newState = get(newIndex);
|
||||
invokeHandlers(oldState, newState);
|
||||
}
|
||||
|
||||
@@ -147,8 +154,15 @@ public class DefaultConcurrentStateMachine<S> extends AbstractStateMachine<S> im
|
||||
return get(index.get());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateCurrentIndex(int newIndex) {
|
||||
this.index.set(newIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否为默认状态
|
||||
*
|
||||
* @return 默认状态时返回真, 否则返回假.
|
||||
*/
|
||||
protected boolean isDefault() {
|
||||
return index.get() == 0;
|
||||
@@ -156,7 +170,9 @@ public class DefaultConcurrentStateMachine<S> extends AbstractStateMachine<S> im
|
||||
|
||||
/**
|
||||
* 移动下标至上一个状态
|
||||
* <li> 使用CAS一直尝试, 直到成功
|
||||
* <p>
|
||||
* 使用CAS一直尝试, 直到成功
|
||||
* </p>
|
||||
*/
|
||||
protected void exchangeToPrev() {
|
||||
final int size = size();
|
||||
@@ -168,7 +184,9 @@ public class DefaultConcurrentStateMachine<S> extends AbstractStateMachine<S> im
|
||||
|
||||
/**
|
||||
* 移动下标至下一个状态
|
||||
* <li> 使用CAS一直尝试, 直到成功
|
||||
* <p>
|
||||
* 使用CAS一直尝试, 直到成功
|
||||
* </p>
|
||||
*/
|
||||
protected void exchangeToNext() {
|
||||
final int size = size();
|
||||
@@ -180,7 +198,9 @@ public class DefaultConcurrentStateMachine<S> extends AbstractStateMachine<S> im
|
||||
|
||||
/**
|
||||
* 切换到指定状态值
|
||||
* <li> 使用CAS一直尝试, 直到成功
|
||||
* <p>
|
||||
* 使用CAS一直尝试, 直到成功
|
||||
* </p>
|
||||
*
|
||||
* @param target 目标值
|
||||
*/
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -31,8 +31,15 @@ public class StandardStateMachine<S> extends AbstractStateMachine<S> implements
|
||||
Map<String, List<StateHandlerWrapper<S>>> exchangeHandlers,
|
||||
Map<Object, List<Consumer<StateMachine<S>>>> eventRegistries,
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -5,11 +5,13 @@ import com.serliunx.statemanagement.manager.BidirectionalStateManager;
|
||||
/**
|
||||
* 状态机定义
|
||||
* <p>
|
||||
* 基于双向的状态管理器扩展 {@link BidirectionalStateManager}, 切换逻辑依赖于内置的状态管理器;
|
||||
* 同时可以多种监听事件, 包括:
|
||||
* 基于双向的状态管理器扩展 {@link BidirectionalStateManager};
|
||||
* 同时可以监听多种事件和发布事件, 包括:
|
||||
* <ul>
|
||||
* <li> 切换至指定状态时触发 (进入事件)
|
||||
* <li> 切出指定状态时触发 (离开事件)
|
||||
* <li> 从A切换到B状态时触发 (交换事件)
|
||||
* </ul>
|
||||
* <p>
|
||||
* 请使用 {@link StateMachineBuilder} 来构建状态机.
|
||||
*
|
||||
@@ -77,7 +79,9 @@ public interface StateMachine<S> extends BidirectionalStateManager<S>, AutoClose
|
||||
|
||||
/**
|
||||
* 切换至指定状态
|
||||
* <li> 在使用状态机的情况, 仅切换成功才会触发注册的各种事件.
|
||||
* <p>
|
||||
* 在使用状态机的情况, 仅切换成功才会触发注册的各种事件.
|
||||
* </p>
|
||||
*
|
||||
* @param invokeHandlers 是否唤醒状态处理器
|
||||
* @param state 新的状态
|
||||
@@ -94,7 +98,9 @@ public interface StateMachine<S> extends BidirectionalStateManager<S>, AutoClose
|
||||
|
||||
/**
|
||||
* 切换至指定状态
|
||||
* <li> 在使用状态机的情况, 仅切换成功才会触发注册的各种事件.
|
||||
* <p>
|
||||
* 在使用状态机的情况, 仅切换成功才会触发注册的各种事件.
|
||||
* </p>
|
||||
*
|
||||
* @param state 新的状态
|
||||
* @return 切换成功返回真, 否则返回假
|
||||
|
||||
@@ -14,7 +14,7 @@ import java.util.function.Consumer;
|
||||
* @version 1.0.0
|
||||
* @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 S initialState;
|
||||
|
||||
/**
|
||||
* 各种事件
|
||||
@@ -49,17 +53,18 @@ public final class StateMachineBuilder<S> {
|
||||
this(Arrays.asList(states));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 添加交换事件
|
||||
* <li> 从A状态切换至B状态时触发
|
||||
* 定义初始状态
|
||||
*
|
||||
* @param from 源状态
|
||||
* @param to 目的状态
|
||||
* @param handler 处理器
|
||||
* @param async 是否异步执行
|
||||
* @param executor 异步执行器, 异步执行时将使用, 不指定时将使用状态机内置的执行器
|
||||
* @param initialState 初始状态
|
||||
* @return 状态机构建
|
||||
*/
|
||||
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) {
|
||||
final String key = from.toString() + "-" + to.toString();
|
||||
final List<StateHandlerWrapper<S>> stateHandlerWrappers = exchangeHandlers.computeIfAbsent(key,
|
||||
@@ -68,40 +73,17 @@ public final class StateMachineBuilder<S> {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加交换事件
|
||||
* <li> 从A状态切换至B状态时触发
|
||||
*
|
||||
* @param from 源状态
|
||||
* @param to 目的状态
|
||||
* @param handler 处理器
|
||||
* @param async 是否异步执行
|
||||
*/
|
||||
@Override
|
||||
public StateMachineBuilder<S> exchange(S from, S to, StateHandler<S> handler, Boolean async) {
|
||||
return exchange(from, to, handler, async, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加交换事件
|
||||
* <li> 从A状态切换至B状态时触发
|
||||
*
|
||||
* @param from 源状态
|
||||
* @param to 目的状态
|
||||
* @param handler 处理器
|
||||
*/
|
||||
@Override
|
||||
public StateMachineBuilder<S> exchange(S from, S to, StateHandler<S> handler) {
|
||||
return exchange(from, to, handler, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加离开事件
|
||||
* <li> 从指定状态切换到别的状态时执行的逻辑
|
||||
*
|
||||
* @param state 状态
|
||||
* @param handler 处理逻辑
|
||||
* @param async 是否异步执行
|
||||
* @param executor 异步执行器, 异步执行时将使用, 不指定时将使用状态机内置的执行器
|
||||
*/
|
||||
@Override
|
||||
public StateMachineBuilder<S> whenLeave(S state, StateHandler<S> handler, Boolean async, Executor executor) {
|
||||
final List<StateHandlerWrapper<S>> stateHandlerWrappers = leaveHandlers.computeIfAbsent(state,
|
||||
k -> new ArrayList<>());
|
||||
@@ -109,38 +91,17 @@ public final class StateMachineBuilder<S> {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加离开事件
|
||||
* <li> 从指定状态切换到别的状态时执行的逻辑
|
||||
*
|
||||
* @param state 状态
|
||||
* @param handler 处理逻辑
|
||||
* @param async 是否异步执行
|
||||
*/
|
||||
@Override
|
||||
public StateMachineBuilder<S> whenLeave(S state, StateHandler<S> handler, Boolean async) {
|
||||
return whenLeave(state, handler, async, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加离开事件
|
||||
* <li> 从指定状态切换到别的状态时执行的逻辑
|
||||
*
|
||||
* @param state 状态
|
||||
* @param handler 处理逻辑
|
||||
*/
|
||||
@Override
|
||||
public StateMachineBuilder<S> whenLeave(S state, StateHandler<S> handler) {
|
||||
return whenLeave(state, handler, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加进入事件
|
||||
* <li> 切换到了指定状态时执行的逻辑
|
||||
*
|
||||
* @param state 状态
|
||||
* @param handler 处理逻辑
|
||||
* @param async 是否异步执行
|
||||
* @param executor 异步执行器, 异步执行时将使用, 不指定时将使用状态机内置的执行器
|
||||
*/
|
||||
@Override
|
||||
public StateMachineBuilder<S> whenEntry(S state, StateHandler<S> handler, Boolean async, Executor executor) {
|
||||
final List<StateHandlerWrapper<S>> stateHandlerWrappers = entryHandlers.computeIfAbsent(state,
|
||||
k -> new ArrayList<>());
|
||||
@@ -148,25 +109,12 @@ public final class StateMachineBuilder<S> {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加进入事件
|
||||
* <li> 切换到了指定状态时执行的逻辑
|
||||
*
|
||||
* @param state 状态
|
||||
* @param handler 处理逻辑
|
||||
* @param async 是否异步执行
|
||||
*/
|
||||
@Override
|
||||
public StateMachineBuilder<S> whenEntry(S state, StateHandler<S> handler, Boolean async) {
|
||||
return whenEntry(state, handler, async, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加进入事件
|
||||
* <li> 切换到了指定状态时执行的逻辑
|
||||
*
|
||||
* @param state 状态
|
||||
* @param handler 处理逻辑
|
||||
*/
|
||||
@Override
|
||||
public StateMachineBuilder<S> whenEntry(S state, StateHandler<S> handler) {
|
||||
return whenEntry(state, handler, null);
|
||||
}
|
||||
@@ -176,6 +124,7 @@ public final class StateMachineBuilder<S> {
|
||||
*
|
||||
* @param event 事件
|
||||
* @param logic 切换逻辑
|
||||
* @return 当前对象, 链式调用
|
||||
*/
|
||||
public StateMachineBuilder<S> whenHappened(Object event, Consumer<StateMachine<S>> logic) {
|
||||
List<Consumer<StateMachine<S>>> consumers = eventRegistries.computeIfAbsent(event, k -> new ArrayList<>());
|
||||
@@ -189,6 +138,7 @@ public final class StateMachineBuilder<S> {
|
||||
* 优先级低于添加事件时指定的执行器
|
||||
*
|
||||
* @param executor 执行器
|
||||
* @return 当前对象, 链式调用
|
||||
*/
|
||||
public StateMachineBuilder<S> executor(Executor executor) {
|
||||
this.executor = executor;
|
||||
@@ -199,6 +149,7 @@ public final class StateMachineBuilder<S> {
|
||||
* 定义状态机是否异步执行
|
||||
*
|
||||
* @param async 是否异步执行
|
||||
* @return 当前对象, 链式调用
|
||||
*/
|
||||
public StateMachineBuilder<S> async(Boolean async) {
|
||||
this.async = async;
|
||||
@@ -207,6 +158,8 @@ public final class StateMachineBuilder<S> {
|
||||
|
||||
/**
|
||||
* 定义状态机为异步执行
|
||||
*
|
||||
* @return 当前对象, 链式调用
|
||||
*/
|
||||
public StateMachineBuilder<S> async() {
|
||||
return async(true);
|
||||
@@ -214,9 +167,12 @@ public final class StateMachineBuilder<S> {
|
||||
|
||||
/**
|
||||
* 指定状态机的类型
|
||||
* <li> 状态机并发与否并不影响事件的执行逻辑
|
||||
* <p>
|
||||
* 状态机并发与否并不影响事件的执行逻辑
|
||||
* </p>
|
||||
*
|
||||
* @param type 类型
|
||||
* @return 当前对象, 链式调用
|
||||
*/
|
||||
public StateMachineBuilder<S> type(StateMachineType type) {
|
||||
if (type == null) {
|
||||
@@ -228,7 +184,11 @@ public final class StateMachineBuilder<S> {
|
||||
|
||||
/**
|
||||
* 指定状态机的类型为标准型
|
||||
* <li> 状态机并发与否并不影响事件的执行逻辑
|
||||
* <p>
|
||||
* 状态机并发与否并不影响事件的执行逻辑
|
||||
* </p>
|
||||
*
|
||||
* @return 当前对象, 链式调用
|
||||
*/
|
||||
public StateMachineBuilder<S> standard() {
|
||||
return type(StateMachineType.STANDARD);
|
||||
@@ -236,14 +196,21 @@ public final class StateMachineBuilder<S> {
|
||||
|
||||
/**
|
||||
* 指定状态机的类型为并发型
|
||||
* <li> 状态机并发与否并不影响事件的执行逻辑
|
||||
* <p>
|
||||
* 状态机并发与否并不影响事件的执行逻辑
|
||||
* </p>
|
||||
*
|
||||
* @return 当前对象, 链式调用
|
||||
*/
|
||||
public StateMachineBuilder<S> concurrent() {
|
||||
return type(StateMachineType.CONCURRENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建
|
||||
* 执行构建
|
||||
*
|
||||
* @param <M> 状态机类型
|
||||
* @return 状态机
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <M extends StateMachine<S>> M build() {
|
||||
@@ -252,10 +219,10 @@ public final class StateMachineBuilder<S> {
|
||||
}
|
||||
if (type.equals(StateMachineType.STANDARD)) {
|
||||
return (M)new StandardStateMachine<>(stateList, entryHandlers,
|
||||
leaveHandlers, exchangeHandlers, eventRegistries, executor, async);
|
||||
leaveHandlers, exchangeHandlers, eventRegistries, executor, async, initialState);
|
||||
} else if (type.equals(StateMachineType.CONCURRENT)) {
|
||||
return (M)new DefaultConcurrentStateMachine<>(stateList, entryHandlers,
|
||||
leaveHandlers, exchangeHandlers, eventRegistries, executor, async);
|
||||
leaveHandlers, exchangeHandlers, eventRegistries, executor, async, initialState);
|
||||
}
|
||||
throw new IllegalArgumentException("未知的状态机类型: " + type);
|
||||
}
|
||||
@@ -263,6 +230,7 @@ public final class StateMachineBuilder<S> {
|
||||
/**
|
||||
* 状态机构建器
|
||||
*
|
||||
* @param <S> 状态类型
|
||||
* @param states 状态集合
|
||||
* @return 状态机构建器实例
|
||||
*/
|
||||
@@ -273,6 +241,7 @@ public final class StateMachineBuilder<S> {
|
||||
/**
|
||||
* 状态机构建器
|
||||
*
|
||||
* @param <S> 状态类型
|
||||
* @param states 状态集合
|
||||
* @return 状态机构建器实例
|
||||
*/
|
||||
|
||||
@@ -1,58 +1,144 @@
|
||||
package com.serliunx.statemanagement.machine;
|
||||
|
||||
import com.serliunx.statemanagement.machine.handler.StateHandler;
|
||||
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.Map;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* 状态机上下文集合, 用于构建参数封装
|
||||
*
|
||||
* @author <a href="mailto:serliunx@yeah.net">SerLiunx</a>
|
||||
* @version 1.0.0
|
||||
* @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>
|
||||
* 当具体的执行器没有指定是否异步时, 将根据该值决定是否异步执行.
|
||||
*/
|
||||
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<String, List<StateHandlerWrapper<S>>> exchangeHandlers,
|
||||
Map<Object, List<Consumer<StateMachine<S>>>> eventRegistries,
|
||||
Executor executor,
|
||||
Boolean async
|
||||
) {
|
||||
this.entryHandlers = entryHandlers;
|
||||
this.leaveHandlers = leaveHandlers;
|
||||
this.exchangeHandlers = exchangeHandlers;
|
||||
this.executor = executor;
|
||||
this.async = async;
|
||||
this.eventRegistries = eventRegistries;
|
||||
this(entryHandlers, leaveHandlers, exchangeHandlers, eventRegistries, executor, async, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StateMachineContext<S> whenEntry(S state, StateHandler<S> handler, Boolean async, Executor executor) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ public enum StateMachineType {
|
||||
* 标准, 切换使用读写锁
|
||||
*/
|
||||
STANDARD,
|
||||
|
||||
/**
|
||||
* 并发型, 切换使用CAS乐观锁
|
||||
*/
|
||||
|
||||
48
src/main/java/com/serliunx/statemanagement/machine/external/FlexibleStateMachine.java
vendored
Normal file
48
src/main/java/com/serliunx/statemanagement/machine/external/FlexibleStateMachine.java
vendored
Normal 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);
|
||||
}
|
||||
@@ -9,7 +9,6 @@ package com.serliunx.statemanagement.machine.handler;
|
||||
* @version 1.0.0
|
||||
* @since 2024/12/28
|
||||
*/
|
||||
@SuppressWarnings("all")
|
||||
public final class StateHandlerProcessParams<S> {
|
||||
|
||||
/**
|
||||
@@ -29,7 +28,6 @@ public final class StateHandlerProcessParams<S> {
|
||||
* @param from 原状态
|
||||
* @param to 目标状态
|
||||
* @param attach 附加参数
|
||||
* @param bidirectionalStateManager 状态机内置的状态管理器
|
||||
*/
|
||||
public StateHandlerProcessParams(S from, S to, Object attach) {
|
||||
this.from = from;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
}
|
||||
@@ -11,7 +11,6 @@ import java.util.concurrent.Executor;
|
||||
* @version 1.0.0
|
||||
* @since 2024/12/28
|
||||
*/
|
||||
@SuppressWarnings("all")
|
||||
public final class StateHandlerWrapper<S> {
|
||||
|
||||
/**
|
||||
@@ -20,7 +19,8 @@ public final class StateHandlerWrapper<S> {
|
||||
private final StateHandler<S> stateHandler;
|
||||
/**
|
||||
* 执行器
|
||||
* <li> 用于异步执行处理逻辑
|
||||
* <p>
|
||||
* 用于异步执行处理逻辑
|
||||
*/
|
||||
private final Executor executor;
|
||||
/**
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,11 @@ public abstract class AbstractStateManager<S> implements StateManager<S> {
|
||||
*/
|
||||
private volatile int index;
|
||||
|
||||
/**
|
||||
* 默认状态序号
|
||||
*/
|
||||
private int defaultIndex = 0;
|
||||
|
||||
/**
|
||||
* 锁
|
||||
*/
|
||||
@@ -105,15 +110,12 @@ public abstract class AbstractStateManager<S> implements StateManager<S> {
|
||||
return stateList.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSwitchable() {
|
||||
return stateList.size() > 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将序号移动至下一个
|
||||
* <ul>
|
||||
* <li> 自动归零
|
||||
* <li> 仅在持有写锁的情况下访问
|
||||
* </ul>
|
||||
*/
|
||||
@SuppressWarnings("all")
|
||||
protected void next() {
|
||||
@@ -123,13 +125,15 @@ public abstract class AbstractStateManager<S> implements StateManager<S> {
|
||||
|
||||
/**
|
||||
* 将序号移动至上一个
|
||||
* <ul>
|
||||
* <li> 自动归零
|
||||
* <li> 仅在持有写锁的情况下访问
|
||||
* </ul>
|
||||
*/
|
||||
@SuppressWarnings("all")
|
||||
protected void prev() {
|
||||
if (--index < 0)
|
||||
index = 0;
|
||||
index = stateList.size() - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -137,7 +141,9 @@ public abstract class AbstractStateManager<S> implements StateManager<S> {
|
||||
* <p>
|
||||
* 类及子类访问当前状态时不允许使用{@link #current()},因为会造成死锁
|
||||
*
|
||||
* <li> 仅在持有锁的情况下访问
|
||||
* <p>
|
||||
* 仅在持有锁的情况下访问
|
||||
* </p>
|
||||
*
|
||||
* @return 当前状态
|
||||
*/
|
||||
@@ -162,6 +168,9 @@ public abstract class AbstractStateManager<S> implements StateManager<S> {
|
||||
* @return 序号 {@link List#indexOf(Object)}
|
||||
*/
|
||||
protected int indexOf(S state) {
|
||||
if (state == null) {
|
||||
return -1;
|
||||
}
|
||||
return stateList.indexOf(state);
|
||||
}
|
||||
|
||||
@@ -180,7 +189,7 @@ public abstract class AbstractStateManager<S> implements StateManager<S> {
|
||||
* @return 是第一个时返回真, 否则返回假.
|
||||
*/
|
||||
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) {
|
||||
index = newIndex;
|
||||
@@ -201,8 +212,19 @@ public abstract class AbstractStateManager<S> implements StateManager<S> {
|
||||
|
||||
/**
|
||||
* 状态序号默认值(等同于默认状态)
|
||||
*
|
||||
* @return 默认的状态值
|
||||
*/
|
||||
protected int getDefault() {
|
||||
return 0;
|
||||
return defaultIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置默认值
|
||||
*
|
||||
* @param defaultIndex 默认值
|
||||
*/
|
||||
protected void setDefault(int defaultIndex) {
|
||||
this.defaultIndex = defaultIndex;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,8 +6,10 @@ import java.util.List;
|
||||
|
||||
/**
|
||||
* 断路的单向状态管理器
|
||||
* <p> 逻辑与{@link UnidirectionalStateManager}大体相同, 不同的点在于:
|
||||
* <li> 最后一个状态无法转向第一个状态, 即为一次性的状态管理器.
|
||||
* <p>
|
||||
* 逻辑与{@link UnidirectionalStateManager}大体相同, 不同的点在于:
|
||||
* 最后一个状态无法转向第一个状态, 即为一次性的状态管理器.
|
||||
* </p>
|
||||
*
|
||||
* @author <a href="mailto:serliunx@yeah.net">SerLiunx</a>
|
||||
* @version 1.0.0
|
||||
|
||||
@@ -2,7 +2,9 @@ package com.serliunx.statemanagement.manager;
|
||||
|
||||
/**
|
||||
* 将指定状态管理器标记为循环的状态管理器
|
||||
* <li> 允许单向、双向循环
|
||||
* <p>
|
||||
* 允许单向、双向循环
|
||||
* </p>
|
||||
*
|
||||
* @author <a href="mailto:serliunx@yeah.net">SerLiunx</a>
|
||||
* @version 1.0.0
|
||||
|
||||
@@ -83,6 +83,9 @@ public class DefaultUnidirectionalStateManager<S> extends AbstractStateManager<S
|
||||
|
||||
/**
|
||||
* 保留默认的切换方式供子类使用
|
||||
*
|
||||
* @param state 目标状态值
|
||||
* @return 成功切换返回真, 否则返回假
|
||||
*/
|
||||
protected boolean defaultSwitchTo(S state) {
|
||||
return super.switchTo(state);
|
||||
|
||||
@@ -33,16 +33,60 @@ public interface StateManager<S> {
|
||||
|
||||
/**
|
||||
* 获取当前状态数量
|
||||
*
|
||||
* @return 数量
|
||||
*/
|
||||
int size();
|
||||
|
||||
/**
|
||||
* 是否可切换
|
||||
* <p>
|
||||
* 默认情况下, 状态集合中的状态数量大于1时就可以切换。部分实现在特定情况下可能不允许切换,
|
||||
* 比如断路的单向状态管理器 {@link BreakageUnidirectionalStateManager}, 当状态为最后一个时
|
||||
* 则不允许向前、或者向后切换
|
||||
* </p>
|
||||
*
|
||||
* @return 可切换返回真, 否则返回假
|
||||
*/
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,13 +4,13 @@ package com.serliunx.statemanagement.manager;
|
||||
* 单向流转的状态管理器
|
||||
* <p>
|
||||
* 其基本逻辑等同于 {@link StateManager}, 但存在以下不同:
|
||||
* <li> 状态只能单方向流动(最后一个状态允许切换至第一个状态), 如果有A, B, C, D 四种状态则存在以下几种情况:
|
||||
* <p>
|
||||
* <p>
|
||||
* <li> A -> B 允许直接切换, A -> C 允许直接切换, C -> D 允许直接切换 等等..
|
||||
* <li> B -> A 不允许切换, C -> A 不允许切换, D -> C 不允许切换 等等..
|
||||
* <li> 特例: D -> A 是允许的, 因为D是最后一个状态, 故可以切换至第一个状态.
|
||||
* <p>
|
||||
* 状态只能单方向流动(最后一个状态允许切换至第一个状态), 如果有A, B, C, D 四种状态则存在以下几种情况:
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li> A 至 B 允许直接切换, A 至 C 允许直接切换, C 至 D 允许直接切换 等等..
|
||||
* <li> B 至 A 不允许切换, C 至 A 不允许切换, D 至 C 不允许切换 等等..
|
||||
* <li> 特例: D 至 A 是允许的, 因为 D 是最后一个状态, 故可以切换至第一个状态.
|
||||
* </ul>
|
||||
* 即状态的切换只允许一个方向,不允许向前流动,除非到达最后一个状态!
|
||||
*
|
||||
* @author <a href="mailto:serliunx@yeah.net">SerLiunx</a>
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,10 @@
|
||||
package com.serliunx.statemanagement.support;
|
||||
|
||||
import java.util.concurrent.*;
|
||||
|
||||
/**
|
||||
* 线程池相关工具类
|
||||
*
|
||||
* @author <a href="mailto:serliunx@yeah.net">SerLiunx</a>
|
||||
* @version 1.0.0
|
||||
* @since 2024/12/28
|
||||
@@ -8,4 +12,21 @@ package com.serliunx.statemanagement.support;
|
||||
public final class ExecutorUtils {
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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()));
|
||||
}
|
||||
}
|
||||
@@ -5,10 +5,13 @@ import com.serliunx.statemanagement.machine.StateMachine;
|
||||
import com.serliunx.statemanagement.machine.StateMachineBuilder;
|
||||
import com.serliunx.statemanagement.support.PrinterEvent;
|
||||
import com.serliunx.statemanagement.support.PrinterState;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
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.TimeUnit;
|
||||
|
||||
/**
|
||||
* 状态机测试
|
||||
@@ -17,49 +20,58 @@ import java.util.concurrent.Executors;
|
||||
* @version 1.0.0
|
||||
* @since 2024/12/28
|
||||
*/
|
||||
@Slf4j
|
||||
public class MachineTest {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(MachineTest.class);
|
||||
|
||||
private final ExecutorService executor = Executors.newFixedThreadPool(5);
|
||||
|
||||
@Test
|
||||
public void testStandardStateMachine() throws Exception {
|
||||
StateMachine<PrinterState> stateMachine = StateMachineBuilder.from(PrinterState.values())
|
||||
.async(false)
|
||||
.async(true)
|
||||
.standard()
|
||||
.executor(Executors.newFixedThreadPool(16))
|
||||
.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);
|
||||
})
|
||||
.withInitial(PrinterState.STOPPING)
|
||||
.build();
|
||||
|
||||
stateMachine.publish(PrinterEvent.TURN_ON);
|
||||
|
||||
stateMachine.close();
|
||||
log.info("{}", stateMachine.current());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConcurrentStateMachine() throws Exception {
|
||||
ConcurrentStateMachine<PrinterState> stateMachine = StateMachineBuilder.from(PrinterState.values())
|
||||
.async(false)
|
||||
.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()
|
||||
.build();
|
||||
|
||||
System.out.println(stateMachine.compareAndSet(PrinterState.IDLE, PrinterState.STOPPING, true));
|
||||
|
||||
log.info("{}", stateMachine.current());
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
package com.serliunx.statemanagement;
|
||||
|
||||
import com.serliunx.statemanagement.manager.BreakageUnidirectionalStateManager;
|
||||
import com.serliunx.statemanagement.manager.DefaultUnidirectionalStateManager;
|
||||
import com.serliunx.statemanagement.manager.UnidirectionalStateManager;
|
||||
import com.serliunx.statemanagement.manager.*;
|
||||
import com.serliunx.statemanagement.support.PrinterState;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.junit.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* 状态管理器测试
|
||||
@@ -14,9 +13,10 @@ import org.junit.Test;
|
||||
* @version 1.0.0
|
||||
* @since 2024/12/28
|
||||
*/
|
||||
@Slf4j
|
||||
public class ManagerTest {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(ManagerTest.class);
|
||||
|
||||
@Test
|
||||
public void testUnidirectionalStateManager() {
|
||||
UnidirectionalStateManager<PrinterState> unidirectionalStateManager =
|
||||
@@ -35,4 +35,17 @@ public class ManagerTest {
|
||||
}
|
||||
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~");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
15
src/test/resources/logback.xml
Normal file
15
src/test/resources/logback.xml
Normal 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>
|
||||
Reference in New Issue
Block a user