squirrel-foundation is a State Machine library, which provided a lightweight, easy use, type safe and programmable state machine implementation for Java.
Sometimes (rarely) I encounter the following exception:
java.util.ConcurrentModificationException: null
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909) ~[na:1.8.0_161]
at java.util.ArrayList$Itr.next(ArrayList.java:859) ~[na:1.8.0_161]
at java.util.Collections$UnmodifiableCollection$1.next(Collections.java:1042) ~[na:1.8.0_161]
at org.squirrelframework.foundation.fsm.impl.StateImpl.entry(StateImpl.java:128) ~[squirrel-foundation-0.3.8.jar:na]
at org.squirrelframework.foundation.fsm.impl.TimedStateImpl.entry(TimedStateImpl.java:17) ~[squirrel-foundation-0.3.8.jar:na]
at org.squirrelframework.foundation.fsm.impl.StateImpl.enterShallow(StateImpl.java:271) ~[squirrel-foundation-0.3.8.jar:na]
at org.squirrelframework.foundation.fsm.impl.TimedStateImpl.enterShallow(TimedStateImpl.java:17) ~[squirrel-foundation-0.3.8.jar:na]
at org.squirrelframework.foundation.fsm.impl.StateImpl.enterHistoryNone(StateImpl.java:295) ~[squirrel-foundation-0.3.8.jar:na]
at org.squirrelframework.foundation.fsm.impl.StateImpl.enterByHistory(StateImpl.java:248) ~[squirrel-foundation-0.3.8.jar:na]
at org.squirrelframework.foundation.fsm.impl.TransitionImpl.internalFire(TransitionImpl.java:203) ~[squirrel-foundation-0.3.8.jar:na]
at org.squirrelframework.foundation.fsm.impl.StateImpl.internalFire(StateImpl.java:419) ~[squirrel-foundation-0.3.8.jar:na]
at org.squirrelframework.foundation.fsm.impl.TimedStateImpl.internalFire(TimedStateImpl.java:17) ~[squirrel-foundation-0.3.8.jar:na]
at org.squirrelframework.foundation.fsm.impl.AbstractStateMachine.processEvent(AbstractStateMachine.java:161) ~[squirrel-foundation-0.3.8.jar:na]
at org.squirrelframework.foundation.fsm.impl.AbstractStateMachine.processEvents(AbstractStateMachine.java:215) ~[squirrel-foundation-0.3.8.jar:na]
at org.squirrelframework.foundation.fsm.impl.AbstractStateMachine.internalFire(AbstractStateMachine.java:248) ~[squirrel-foundation-0.3.8.jar:na]
at org.squirrelframework.foundation.fsm.impl.AbstractStateMachine.fire(AbstractStateMachine.java:268) ~[squirrel-foundation-0.3.8.jar:na]
at org.squirrelframework.foundation.fsm.impl.AbstractStateMachine.fire(AbstractStateMachine.java:279) ~[squirrel-foundation-0.3.8.jar:na]
Since I am unable to find code paths of action list modifications during FSM execution, I guess this is a memory visibility issue. The quick fix I use:
static {
// must be called before org.squirrelframework.foundation.fsm.impl.FSM.newActions()
SquirrelProvider.getInstance().register(Actions.class, ThreadSafeActionsImpl.class);
}
public static class ThreadSafeActionsImpl<T extends StateMachine<T, S, E, C>, S, E, C>
implements Actions<T, S, E, C> {
private static final Comparator<Action<?, ?, ?, ?>> ACTION_COMPARATOR =
(o1, o2) -> o2.weight() - o1.weight();
private final SortedSet<Action<T, S, E, C>> actions =
Collections.synchronizedSortedSet(new TreeSet<>(ACTION_COMPARATOR));
@Override
public void add(Action<T, S, E, C> newAction) {
actions.add(newAction);
}
@Override
public void addAll(List<? extends Action<T, S, E, C>> newActions) {
actions.addAll(newActions);
}
@Override
public List<Action<T, S, E, C>> getAll() {
return Collections.unmodifiableList(new ArrayList<>(actions));
}
@Override
public void clear() {
throw new UnsupportedOperationException("not implemented");
}
}
Sometimes (rarely) I encounter the following exception:
Since I am unable to find code paths of action list modifications during FSM execution, I guess this is a memory visibility issue. The quick fix I use: