synchronized在workflow中用于保障节点内共享资源线程安全,而非流程调度;适用于javadelegate等场景中防止多线程并发修改局部状态,需按流程实例id细粒度加锁并避免跨jvm失效。

synchronized 的重入锁机制在 Workflow 工作流场景中不是直接“用于工作流引擎本身”,而是常被开发者用来保障工作流节点内共享资源的线程安全。它不参与流程调度、状态持久化或事务协调,但能在单个节点(如服务任务、脚本任务)内部,防止多线程并发修改局部状态、缓存、计数器或临时上下文对象时出现数据错乱。
重入锁在工作流节点内的典型适用场景
Workflow 引擎(如 Activiti、Flowable、Camunda)通常以单线程方式执行每个任务实例;但在以下情况可能触发多线程并发:
- 自定义 JavaDelegate 或 ExecutionListener 中调用了异步回调、线程池提交任务,或复用共享工具类(如静态计数器、本地缓存 Map)
- 同一工作流实例被多个事件(如定时器、消息到达)同时触发,导致多个线程进入同一个委托类的同一方法
- 批量启动多个流程实例,且它们共用某个全局配置对象或连接池管理器
为什么用 synchronized 而不是 ReentrantLock?
在轻量级、短临界区、无中断/超时需求的节点逻辑中,synchronized 更简洁可靠:
- 自动加锁/解锁:不会因异常遗漏 unlock,避免死锁风险
- 天然可重入:同一节点方法内嵌套调用另一个同步方法(如
doProcess()→updateStatus()),无需额外判断 - 锁对象明确:可用
this(委托实例)、execution.getProcessInstanceId()(按流程实例粒度隔离)、或专用锁对象(如private final Object lock = new Object();)
实际写法示例(JavaDelegate 场景)
假设一个订单审批节点需更新共享内存中的审批次数统计:
public class ApprovalCounterDelegate implements JavaDelegate {
private static final Map<string integer> INSTANCE_COUNTER = new ConcurrentHashMap();
private final Object instanceLock = new Object();
@Override
public void execute(DelegateExecution execution) {
String procId = execution.getProcessInstanceId();
// ✅ 推荐:用流程实例ID作为锁对象,实现细粒度隔离
synchronized (procId.intern()) {
int count = INSTANCE_COUNTER.getOrDefault(procId, 0);
INSTANCE_COUNTER.put(procId, count + 1);
}
// ❌ 不推荐:用 this 锁,所有实例串行,严重拖慢吞吐
// synchronized (this) { ... }
// ✅ 也可用专用锁对象(适合单实例多线程场景)
// synchronized (instanceLock) { ... }
}
}</string>
需要注意的边界与避坑点
synchronized 在 Workflow 中不是万能解药,需警惕以下问题:
- 不能跨 JVM 或跨节点保证一致性:锁只在当前 JVM 进程内有效,集群部署时需配合分布式锁(如 RedisLock)
- 不能替代事务:数据库操作仍需 Spring @Transactional 保障 ACID,synchronized 只管内存态变量
- 避免锁粒度过大:不要在整个 execute() 方法上加 synchronized,应仅包裹真正共享的临界区
- 慎用字符串或动态对象作锁:如
synchronized (procId)每次新建 String 对象会导致锁失效;应改用procId.intern()或new String(procId).intern()
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











