Spring-statemachine版本:当前最新的1.2.3.RELEASE版本

这几天一直被Action是串行执行搞得很郁闷,写了一个demo专门用来测试:

public static void main(String[] args) throws Throwable {
StateMachineBuilder.Builder<String, String> builder = StateMachineBuilder.builder(); StaticListableBeanFactory beanFactory = new StaticListableBeanFactory(); ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(30);
executor.setKeepAliveSeconds(30000);
executor.setMaxPoolSize(30);
executor.setQueueCapacity(3000);
executor.initialize(); builder.configureConfiguration()
.withConfiguration()
.beanFactory(beanFactory)
.taskExecutor(executor)
.taskScheduler(new ConcurrentTaskScheduler())
.listener(new StateMachineListenerAdapter<String, String>() {
@Override
public void stateEntered(State<String, String> state) {
String id = state == null ? null : state.getId();
System.out.println("entered " + id);
} @Override
public void stateExited(State<String, String> state) {
String id = state == null ? null : state.getId();
System.out.println("exited " + id);
}
}); StateMachineStateConfigurer<String, String> smsConfigurer = builder.configureStates();
smsConfigurer.withStates()
.initial("READY")
.fork("FORK")
.state("TASKS")
.join("JOIN")
.choice("CHOICE")
.state("ERROR")
.and()
.withStates()
.parent("TASKS")
.initial("T1")
.end("T1E")
.and()
.withStates()
.parent("TASKS")
.initial("T2")
.end("T2E"); StateMachineTransitionConfigurer<String, String> smtConfigurer = builder.configureTransitions();
smtConfigurer.withExternal()
.source("READY").target("FORK")
.and()
.withFork()
.source("FORK").target("TASKS")
.and()
.withJoin()
.source("TASKS").target("JOIN")
.and()
.withExternal()
.source("T1").target("T1E")
.action(getAction())
.and()
.withExternal()
.source("T2").target("T2E")
.action(getAction())
.and()
.withExternal()
.source("JOIN").target("CHOICE")
.and()
.withChoice()
.source("CHOICE")
.first("ERROR", c -> true)
.last("READY"); StateMachine<String, String> stateMachine = builder.build(); stateMachine.start();
} public static Action<String, String> getAction() {
return c -> {
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>..");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
;
}
System.out.println("<<<<<<<<<<<<<<<<<<<<<<<<<<..");
};
}
}

打出来的日志是

entered READY
exited READY
entered TASKS
entered T1
>>>>>>>>>>>>>>>>>>>>>>>>>>..
entered T2
<<<<<<<<<<<<<<<<<<<<<<<<<<..
exited T1
entered T1E
>>>>>>>>>>>>>>>>>>>>>>>>>>..
<<<<<<<<<<<<<<<<<<<<<<<<<<..
exited T2
entered T2E
exited TASKS
entered ERROR

如果是并发执行的话,应该像是这样:

>>>>>>>>>>>>>>>>>>>>>>>>>>..
>>>>>>>>>>>>>>>>>>>>>>>>>>..
<<<<<<<<<<<<<<<<<<<<<<<<<<..
<<<<<<<<<<<<<<<<<<<<<<<<<<..

然后趁着周末debug一发,跟着代码一步步走,发现org.springframework.statemachine.config.AbstractStateMachineFactory类中有这段代码:

// 从所有region的transition和当前region的state中抽取出当前region的transition
//
// in代表所有的transition(包括父状态机),stateDatas代表当前region(子状态机)的状态
private Collection<TransitionData<S, E>> resolveTransitionData(Collection<TransitionData<S, E>> in, Collection<StateData<S, E>> stateDatas) {
ArrayList<TransitionData<S, E>> out = new ArrayList<TransitionData<S,E>>(); Collection<Object> states = new ArrayList<Object>();
for (StateData<S, E> stateData : stateDatas) {
states.add(stateData.getParent()); // 抽出父状态机的状态
} for (TransitionData<S, E> transitionData : in) {
S state = transitionData.getState(); // 从下一行代码可以推理得出此处的getState得到的是父状态机的状态
if (state != null && states.contains(state)) { // 核心代码,如果父状态机的状态包含state,就加入到out去当作子状态机的transition,最后返回子状态机的transition集合
out.add(transitionData);
}
} return out;
}

看到了吧,我当时猜测构建transition时还有一个state方法用来标识父状态机的状态,于是到withExternal()后面尝试看看有没有一个叫做state()的方法,结果还真有!

然后代码改成这样:

smtConfigurer
.withExternal()
.source("READY").target("FORK")
.and()
.withFork()
.source("FORK").target("TASKS")
.and()
.withJoin()
.source("TASKS").target("JOIN")
.and()
.withExternal()
.state("TASKS") // 增加本行设置父状态机的状态
.source("T1").target("T1E")
.action(getAction())
.and()
.withExternal()
.state("TASKS") // 增加本行设置父状态机的状态
.source("T2").target("T2E")
.action(getAction())
.and()
.withExternal()
.source("JOIN").target("CHOICE")
.and()
.withChoice()
.source("CHOICE")
.first("ERROR", c -> true)
.last("READY");

结果日志终于并发执行了,好开心啊~

entered READY
exited READY
entered TASKS
entered T2
entered T1
>>>>>>>>>>>>>>>>>>>>>>>>>>..
>>>>>>>>>>>>>>>>>>>>>>>>>>..
<<<<<<<<<<<<<<<<<<<<<<<<<<..
<<<<<<<<<<<<<<<<<<<<<<<<<<..
exited T2
exited T1
entered T2E
entered T1E
exited TASKS
entered SUCCESS

关于设置transition的state,官方的reference并没有相关的说明,所以初次使用spring-statemachine做并发任务状态管理的话,基本上都会遇到这个问题。

Github issue: https://github.com/spring-projects/spring-statemachine/issues/336

Spring-statemachine Action不能并发执行的问题的更多相关文章

  1. spring in action 4th --- quick start

    读spring in action. 环境搭建 quick-start依赖注入 面向切面 1.环境搭建 jdk1.8 gradle 2.12 Intelij idea 2016.2.1 1.1创建一个 ...

  2. Spring in action记录

    最近一段时间重新学习了一遍SPRING,现在对这些笔记整理一下,一来算是对之前的学习有一个交代,二来当是重新学习一次,三来可以留下备份 这次学习中以SPRING IN ACTION 4这学习资料,整书 ...

  3. quartz中设置Job不并发执行

    使用quartz框架可以完成定时任务处理即Job,比如有时候我们设置1个Job每隔5分钟执行1次,后来会发现当前Job启动的时候上一个Job还没有运行结束,这显然不是我们期望的,此时可以设置quart ...

  4. Spring in Action 4th 学习笔记 之 AOP

    前提:本文中的AOP仅限于Spring AOP. 先说说为什么需要AOP 最简单的一个例子就是日志记录,如果想记录一些方法的执行情况,最笨的办法就是修改每一个需要记录的方法.但这,真的很笨... 好的 ...

  5. spring quartz使用多线程并发“陷阱”

    定义一个job:ranJob,设置每秒执行一次,设置不允许覆盖并发执行 <bean id="rankJob" class="com.chinacache.www.l ...

  6. 使用Spring StateMachine框架实现状态机

    spring statemachine刚出来不久,但是对于一些企业的大型应用的使用还是十分有借鉴意义的. 最近使用了下这个,感觉还是挺好的. 下面举个例子来说下吧: 创建一个Spring Boot的基 ...

  7. 【说解】在shell中通过mkfifo创建命名管道来控制多个进程并发执行

    背景: 工作中有两个异地机房需要传数据,数据全名很规范,在某个目录下命名为统一的前缀加上编号.如/path/from/file.{1..100}.而机房间的专线对单个scp进程的传输速度是有限制的,比 ...

  8. 1、Spring In Action 4th笔记(1)

    Spring In Action 4th笔记(1) 2016-12-28 1.Spring是一个框架,致力于减轻JEE的开发,它有4个特点: 1.1 基于POJO(Plain Ordinary Jav ...

  9. SSIS Design3:并发执行

    1,利用优先约束来并发处理数据,Data Flow Task 和 Data Flow Task 1 是并发执行的,而 Data Flow Task2 必须等到 Data Flow Task 和 Dat ...

随机推荐

  1. php查询字符串是否存在 strpos

    /*** 查询字符是否存在于某字符串** @param $haystack 字符串* @param $needle 要查找的字符* @return bool*/function str_exists( ...

  2. 优动漫PAINT-牵牛花画法教程

    喇叭型对画者自身的塑形功力会有较高的要求,作者很靠谱的把他的塑形方式详细呈现了出来~ 对于这样的一个仿真效果的牵牛花完全可以使用优动漫PAINT完成,简单又快捷,软件下载:http://www.don ...

  3. js常见语法错误

    “Missing semicolon.” : “缺少分号.”, “Use the function form of \”use strict\”.” : “使用标准化定义function.”, “Un ...

  4. Session与Token认证机制 前后端分离下如何登录

     字号 1 Web登录涉及到知识点 1.1 HTTP无状态性 HTTP是无状态的,一次请求结束,连接断开,下次服务器再收到请求,它就不知道这个请求是哪个用户发过来的.当然它知道是哪个客户端地址发过来的 ...

  5. [HAOI2016]找相同字符(SAM+DP)

    感觉很水. 因为SAM上一个点的子树大小代表这个点所表示子串的出现次数. 建出广义后缀自动机之后.在\(parent\)树上跑\(DP\),维护\(size[i][1]\),和\(size[i][0] ...

  6. rdesktop 脚本

    [root@Eren liwm]# cat rdesktop.sh #!/bin/bash -rdesktop -u user  192.168.122.10 -r sound:local -g 10 ...

  7. 关于数组array_diff(array1, array2)求差集来比较数组是否相等的问题细究

    无意中发现很多朋友都喜欢使用array_diff(array1, array2)来判断两个数组是否相等, 我自己也偶尔会这么使用 但是今天我在写代码的过程中无意发现这么做是不准确的. 首先我们来看一下 ...

  8. Docker安装MySQL忽略大小写问题的问题

    原文:Docker安装MySQL忽略大小写问题的问题 连接MySQL: 查看当前mysql的大小写敏感配置show global variables like '%lower_case%';+---- ...

  9. javascript取前n天的日期两种方法

    方法一: var d = new Date(); d = new Date(d.getFullYear(),d.getMonth(),d.getDate()-n); 方法二: var now = ne ...

  10. solr环境搭建&基本使用

    分步指南 solr服务与tomcat整合 solr使用配置步骤 solr使用 推荐分词工具 相关的文章 一.Solr服务与tomcat整合 1.solr相关版本下载路径:http://archive. ...