Apache Ant 上并行的线程安全数学运算

Thread safe math operations in Parallel on Apache Ant

我是运行几个与Ant并行的子任务

这是build.xml的简化内容:

<target name="parallelOperations">
    <var name="port.number" value="9006"/>
    <for list="a,b,c,d,e" param="letter" parallel="true">
        <sequential>
            <echo>Letter @{letter}</echo>
            <math result="port.number" operand1="${port.number}" operation="+" operand2="1" datatype="int"/>
            <echo>${port.number}</echo>
        </sequential>
    </for>
</target>

这是主要结果:

 [echo] Letter c
 [echo] Letter b
 [echo] Letter a
 [echo] Letter d
 [echo] Letter e
 [echo] 9007
 [echo] 9007
 [echo] 9007
 [echo] 9007
 [echo] 9007

这里发生的是对于列表的每个元素,它打印元素的内容和加操作的结果。这里的问题是数学运算不是thread-save,意味着每个运算并发访问变量$port.number,加一个值,然后赋值。

有没有办法用 Ant 实现线程安全?我尝试做的是每个并行运行的子任务,获得一个唯一的端口号。如果有其他办法,应该也是不错的解决方法。

这是来自documentation of parallel:

The primary use case for <parallel> is to run external programs such as an application server, and the JUnit or TestNG test suites at the same time. Anyone trying to run large Ant task sequences in parallel, such as javadoc and javac at the same time, is implicitly taking on the task of identifying and fixing all concurrency bugs the tasks that they run.

因此同步操作取决于用户。可能有两种解决方案:

  1. 或者使用waitfor任务让每个线程等待某个条件为真(例如设置了属性)

  2. 实现自己的同步任务。 This link 描述了一种编写任务的方法,该任务可以获取 id 并对其进行锁定。

第一种方案比较简单,一般用于这种同步。

我将回答我自己的问题并发布具体解决方案,以防万一有人需要它。

这是可行的解决方案:

<target name="ParallelOperations">
<var name="port.number" value="9006"/>
<for list="a,b,c,d" param="letter" parallel="true">
    <sequential>
        <echo>Letter @{letter}</echo>
        <!-- Synchronize the port number -->
        <synchronized id="port.number.lock">
            <echo>@{letter} new port ${port.number}</echo>
            <var name="@{letter}.port.number" value="${port.number}" />
            <math result="port.number" operand1="${port.number}" operation="+" operand2="1" datatype="int"/>
        </synchronized>
        <echo>@{letter} ${@{letter}.port.number}</echo>
        <echo>@{letter} ${@{letter}.port.number}</echo>
        <echo>@{letter} ${@{letter}.port.number}</echo>
        <echo>@{letter} ${@{letter}.port.number}</echo>
        <echo>@{letter} ${@{letter}.port.number}</echo>
        <echo>@{letter} ${@{letter}.port.number}</echo>
        <echo>@{letter} ${@{letter}.port.number}</echo>
        <echo>@{letter} ${@{letter}.port.number}</echo>
        </sequential>
</for>

这是结果:

ParallelOperations:
     [echo] Letter d
     [echo] Letter a
     [echo] Letter c
     [echo] Letter b
     [echo] c new port 9006
     [echo] c 9006
     [echo] b new port 9007
     [echo] c 9006
     [echo] c 9006
     [echo] b 9007
     [echo] c 9006
     [echo] a new port 9008
     [echo] b 9007
     [echo] c 9006
     [echo] b 9007
     [echo] c 9006
     [echo] a 9008
     [echo] d new port 9009
     [echo] c 9006
     [echo] b 9007
     [echo] a 9008
     [echo] d 9009
     [echo] b 9007
     [echo] a 9008
     [echo] d 9009
     [echo] c 9006
     [echo] a 9008
     [echo] b 9007
     [echo] d 9009
     [echo] a 9008
     [echo] b 9007
     [echo] d 9009
     [echo] a 9008
     [echo] b 9007
     [echo] d 9009
     [echo] a 9008
     [echo] d 9009
     [echo] a 9008
     [echo] d 9009
     [echo] d 9009

根据@manouti 的回答,我从 Stefan Fanke 那里选择了同步命令,我使用每个字母创建一个特定变量来存储端口号。

如您所见,每个字母都分配有自己唯一的端口号。