feat: 完善并发型状态机.
This commit is contained in:
@@ -1,11 +1,33 @@
|
|||||||
package com.serliunx.statemanagement.machine;
|
package com.serliunx.statemanagement.machine;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 基本行为与{@link StateMachine} 一致, 最大不同是切换状态不再使用直接的锁机制, 具体由实现类决定
|
||||||
|
* <li> 默认实现{@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
|
||||||
* @since 2025/2/6
|
* @since 2025/2/6
|
||||||
|
* @see DefaultConcurrentStateMachine
|
||||||
*/
|
*/
|
||||||
public interface ConcurrentStateMachine<S> extends StateMachine<S> {
|
public interface ConcurrentStateMachine<S> extends StateMachine<S> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 尝试使用CAS更新状态
|
||||||
|
* <li> 无论是否成功更新都不触发状态处理器
|
||||||
|
*
|
||||||
|
* @param expectedValue 前置状态
|
||||||
|
* @param newValue 更新的状态值
|
||||||
|
* @return 成功更新返回真, 否则返回假
|
||||||
|
*/
|
||||||
boolean compareAndSet(S expectedValue, S newValue);
|
boolean compareAndSet(S expectedValue, S newValue);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 尝试使用CAS更新状态
|
||||||
|
*
|
||||||
|
* @param expectedValue 前置状态
|
||||||
|
* @param newValue 更新的状态值
|
||||||
|
* @param invokeHandlers 是否触发状态处理器, 仅在成功更新时才触发
|
||||||
|
* @return 成功更新返回真, 否则返回假
|
||||||
|
*/
|
||||||
|
boolean compareAndSet(S expectedValue, S newValue, boolean invokeHandlers);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 并发型状态机的默认实现, 内置的状态序列切换使用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
|
||||||
* @since 2025/2/6
|
* @since 2025/2/6
|
||||||
@@ -32,11 +34,24 @@ public class DefaultConcurrentStateMachine<S> extends AbstractStateMachine<S> im
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean compareAndSet(S expectedValue, S newValue) {
|
public boolean compareAndSet(S expectedValue, S newValue) {
|
||||||
|
return compareAndSet(expectedValue, newValue, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean compareAndSet(S expectedValue, S newValue, boolean invokeHandlers) {
|
||||||
int current = indexOf(expectedValue);
|
int current = indexOf(expectedValue);
|
||||||
int newIndex = indexOf(newValue);
|
int newIndex = indexOf(newValue);
|
||||||
if (current == -1 || newIndex == -1)
|
if (current == -1 || newIndex == -1)
|
||||||
return false;
|
return false;
|
||||||
return index.compareAndSet(current, newIndex);
|
|
||||||
|
S oldState = get(index.get());
|
||||||
|
boolean result = index.compareAndSet(current, newIndex);
|
||||||
|
if (result && invokeHandlers) {
|
||||||
|
S newState = get(index.get());
|
||||||
|
invokeHandlers(oldState, newState);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -48,8 +63,11 @@ public class DefaultConcurrentStateMachine<S> extends AbstractStateMachine<S> im
|
|||||||
public void reset(boolean invokeHandlers) {
|
public void reset(boolean invokeHandlers) {
|
||||||
if (isDefault())
|
if (isDefault())
|
||||||
return;
|
return;
|
||||||
|
S oldState = get(index.get());
|
||||||
exchangeToTarget(0);
|
exchangeToTarget(0);
|
||||||
// TODO invokeHandlers
|
S newState = get(index.get());
|
||||||
|
if (invokeHandlers)
|
||||||
|
invokeHandlers(oldState, newState);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -59,14 +77,17 @@ public class DefaultConcurrentStateMachine<S> extends AbstractStateMachine<S> im
|
|||||||
i == index.get()) {
|
i == index.get()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
S oldState = get(index.get());
|
||||||
exchangeToTarget(i);
|
exchangeToTarget(i);
|
||||||
|
if (invokeHandlers)
|
||||||
|
invokeHandlers(oldState, state);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public S switchPrevAndGet(boolean invokeHandlers) {
|
public S switchPrevAndGet(boolean invokeHandlers) {
|
||||||
S oldState = get(index.get());
|
S oldState = get(index.get());
|
||||||
|
exchangeToPrev();
|
||||||
S newState = get(index.get());
|
S newState = get(index.get());
|
||||||
if (invokeHandlers)
|
if (invokeHandlers)
|
||||||
invokeHandlers(oldState, newState);
|
invokeHandlers(oldState, newState);
|
||||||
@@ -75,27 +96,50 @@ public class DefaultConcurrentStateMachine<S> extends AbstractStateMachine<S> im
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public S getAndSwitchPrev(boolean invokeHandlers) {
|
public S getAndSwitchPrev(boolean invokeHandlers) {
|
||||||
return super.getAndSwitchPrev(invokeHandlers);
|
S oldState = get(index.get());
|
||||||
|
exchangeToPrev();
|
||||||
|
S newState = get(index.get());
|
||||||
|
if (invokeHandlers)
|
||||||
|
invokeHandlers(oldState, newState);
|
||||||
|
return oldState;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void switchPrev(boolean invokeHandlers) {
|
public void switchPrev(boolean invokeHandlers) {
|
||||||
super.switchPrev(invokeHandlers);
|
S oldState = get(index.get());
|
||||||
|
exchangeToPrev();
|
||||||
|
S newState = get(index.get());
|
||||||
|
if (invokeHandlers)
|
||||||
|
invokeHandlers(oldState, newState);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public S switchNextAndGet(boolean invokeHandlers) {
|
public S switchNextAndGet(boolean invokeHandlers) {
|
||||||
return super.switchNextAndGet(invokeHandlers);
|
S oldState = get(index.get());
|
||||||
|
exchangeToNext();
|
||||||
|
S newState = get(index.get());
|
||||||
|
if (invokeHandlers)
|
||||||
|
invokeHandlers(oldState, newState);
|
||||||
|
return newState;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public S getAndSwitchNext(boolean invokeHandlers) {
|
public S getAndSwitchNext(boolean invokeHandlers) {
|
||||||
return super.getAndSwitchNext(invokeHandlers);
|
S oldState = get(index.get());
|
||||||
|
exchangeToNext();
|
||||||
|
S newState =get(index.get());
|
||||||
|
if (invokeHandlers)
|
||||||
|
invokeHandlers(oldState, newState);
|
||||||
|
return oldState;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void switchNext(boolean invokeHandlers) {
|
public void switchNext(boolean invokeHandlers) {
|
||||||
super.switchNext(invokeHandlers);
|
S oldState = get(index.get());
|
||||||
|
exchangeToNext();
|
||||||
|
S newState = get(index.get());
|
||||||
|
if (invokeHandlers)
|
||||||
|
invokeHandlers(oldState, newState);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -106,15 +150,32 @@ public class DefaultConcurrentStateMachine<S> extends AbstractStateMachine<S> im
|
|||||||
/**
|
/**
|
||||||
* 是否为默认状态
|
* 是否为默认状态
|
||||||
*/
|
*/
|
||||||
private boolean isDefault() {
|
protected boolean isDefault() {
|
||||||
return index.get() == 0;
|
return index.get() == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 移动下标至上一个状态
|
* 移动下标至上一个状态
|
||||||
|
* <li> 使用CAS一直尝试, 直到成功
|
||||||
*/
|
*/
|
||||||
public void exchangeToPrev() {
|
protected void exchangeToPrev() {
|
||||||
final int size = size();
|
final int size = size();
|
||||||
|
int currentValue;
|
||||||
|
do {
|
||||||
|
currentValue = index.get();
|
||||||
|
} while (!index.compareAndSet(currentValue, currentValue == 0 ? size - 1 : currentValue - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 移动下标至下一个状态
|
||||||
|
* <li> 使用CAS一直尝试, 直到成功
|
||||||
|
*/
|
||||||
|
protected void exchangeToNext() {
|
||||||
|
final int size = size();
|
||||||
|
int currentValue;
|
||||||
|
do {
|
||||||
|
currentValue = index.get();
|
||||||
|
} while (!index.compareAndSet(currentValue, currentValue == size - 1 ? 0 : currentValue + 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -123,7 +184,7 @@ public class DefaultConcurrentStateMachine<S> extends AbstractStateMachine<S> im
|
|||||||
*
|
*
|
||||||
* @param target 目标值
|
* @param target 目标值
|
||||||
*/
|
*/
|
||||||
private void exchangeToTarget(int target) {
|
protected void exchangeToTarget(int target) {
|
||||||
int currentValue;
|
int currentValue;
|
||||||
do {
|
do {
|
||||||
currentValue = index.get();
|
currentValue = index.get();
|
||||||
|
|||||||
@@ -48,4 +48,18 @@ public class MachineTest {
|
|||||||
|
|
||||||
stateMachine.close();
|
stateMachine.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConcurrentStateMachine() throws Exception {
|
||||||
|
ConcurrentStateMachine<PrinterState> stateMachine = StateMachineBuilder.from(PrinterState.values())
|
||||||
|
.whenEntry(PrinterState.STOPPING, h -> {
|
||||||
|
System.out.println(1111);
|
||||||
|
})
|
||||||
|
.concurrent()
|
||||||
|
.build();
|
||||||
|
|
||||||
|
System.out.println(stateMachine.compareAndSet(PrinterState.IDLE, PrinterState.STOPPING, true));
|
||||||
|
|
||||||
|
stateMachine.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user