除了各种类型的任务之外,我们还能标记任务为循环的,多实例的,或者补偿的。标记可以和各种类型的任务联合使用
一、多实例(Multiple Instance):
多实例活动是在业务流程中定义循环固定次数的方式。在编程的概念中,多实例匹配for each结构:它允许执行固定的次数,或者完成子流程在每一个给定的for each的item中,串行或者并行执行。 多实例是一个有额外属性定义的常规活动(被称为多实例特性),这会导致活动在运行时被执行多次。
下面这些活动可以成为多实例活动: - Service Task - Send Task - User Task - Business Rule Task - Script Task - Receive Task - Manual Task - (Embedded) Sub-Process - Call Activity - Transaction Subprocess
网关(Gateway)和事件(Event)不能成为多实例的。 如果一个活动是多实例的,这个活动被底部的三个短线标识。三个水平线表明这是一个并行活动,三个垂直线表明这个一个串行活动
规范要求,为每个实例创建执行的父执行都有以下变量: 1.nrOfInstances: 实例总数 2.nrOfActiveInstances: 当前活跃数,还没有结束的实例。对于串行多实例来说,这个数总是1 3.nrOfCompletedInstances: 已近完成的实例数
这三个变量可以通过execution.getVariable(x)获取 除此之外,每一个被创建的执行都有一个执行本地变量(不会被其他执行所访问,也不会被存储到流程实例层级): loopCounter: 表明for each循环的实例的索引
定义一个多实例活动:
定义一个多实例活动,这个活动的xml元素必须由一个multiInstanceLoopCharacteristics子元素
<multiInstanceLoopCharacteristics isSequential="false|true">
...
</multiInstanceLoopCharacteristics>
这个isSequential属性表明这个实例活动时串行执行还是并行执行。
当流程进入多实例活动时,实例数量只被计算一次。有几种方式配置实例的数量。一种是通过loopCardinality子元素直接指明数量。
<multiInstanceLoopCharacteristics isSequential="false|true">
<loopCardinality>5</loopCardinality>
</multiInstanceLoopCharacteristics>
解析成正数的表达式也可以:
<multiInstanceLoopCharacteristics isSequential="false|true">
<loopCardinality>${nrOfOrders-nrOfCancellations}</loopCardinality>
</multiInstanceLoopCharacteristics>
另一个方式定义流程实例的数量是通过指定一个流程变量的名称,这个流程变量是一个集合,用在loopDataInputRef子元素上。对于集合中的每个项,都将创建一个实例。还可以选择使用inputDataItem子元素为实例设置集合中的特定项。如下面的XML示例所示:
<userTask id="miTasks" name="My Task ${loopCounter}" camunda:assignee="${assignee}">
<multiInstanceLoopCharacteristics isSequential="false">
<loopDataInputRef>assigneeList</loopDataInputRef>
<inputDataItem name="assignee" />
</multiInstanceLoopCharacteristics>
</userTask>
假设变量assigneeList的值包含[kermit, gonzo, foziee]。在上面的代码片段,三个用户任务(User Task)将会被并行创建。每一个执行都有一个名称叫assignee的流程变量,这个流程变量包含集合中的一直值。在本例中,被用作用户任务的指派人
loopDataInputRef和inputDataItem的限制是:
- 名称很难被记住。
- 由于BPMN 2.0模式的限制,它们不能包含表达式。
我们通过在multiInstanceCharacteristics上提供集合和elementVariable属性来解决这个问题:
<userTask id="miTasks" name="My Task" camunda:assignee="${assignee}">
<multiInstanceLoopCharacteristics isSequential="true"
camunda:collection="${myService.resolveUsersForTask()}" camunda:elementVariable="assignee" >
</multiInstanceLoopCharacteristics>
</userTask>
当所有的实例都结束时,多实例活动就结束了。它也可以通过指定一个在每个实例结束时执行的表达式,当表达式执行结果为true时,所有剩下的实例被摧毁,多实例活动结束,流程继续。表达式需要定义在completionCondition子元素里:
<userTask id="miTasks" name="My Task" camunda:assignee="${assignee}">
<multiInstanceLoopCharacteristics isSequential="false"
camunda:collection="assigneeList" camunda:elementVariable="assignee" >
<completionCondition>${nrOfCompletedInstances/nrOfInstances >= 0.6 }</completionCondition>
</multiInstanceLoopCharacteristics>
</userTask>
在这个例子里,将会为assigneeList里的每个元素创建并行多实例任务。当这些任务的60%完成后,其他任务将被删除,流程继续。
二、边界事件和多实例(Boundary Events and Multi-Instance):

当定时器事件被触发的时候,所有的子流程实例都会和摧毁,不管有多少子流程,以及哪一个内部流程活动还没有完成。
三、循环(Loops):
流程引擎本本来是不支持循环标记的。对于多实例来说,固定次数的循环不是一个最佳选择,因为定义的完成条件可能在某些情况下会提前完成(多实例不会完全执行)。 为了绕开这个限制,可以明确的在BPMN流程中画出循环模型来:

四、补偿(Compensation):
如果一个活动被用作补偿另一个活动造成的影响,那么这个活动可以被申明成一个补偿handler。补偿handler不包含在常规的流程中,并且它只在补偿事件抛出后才会执行。

注意 1.补偿handler图标在取消酒店预定的服务任务的底部中间。 2.补偿handler可能没有incoming或者outgoing流程序列。 3.补偿handler必须直接分配给一个补偿边界事件。 4.把一个活动申明成补偿handler,需要将isForCompensation属性设置问true。