Java - CountDownLatch.await() 可以由编译器重新排序吗

标签 java concurrency synchronization wait countdownlatch

我必须在不同的系统上调用操作。另一个系统是高并发、分布式的。因此我通过 MessageBus 集成它。需要一种实现来让调用者等待,直到在总线上收到结果或超时到期。 实现包括三个步骤:首先,我必须将 future 和 CountDownLatch(一旦收到结果就释放)打包到 ConcurrentHashMap 中。该映射与监听 MessageBus 的组件共享。然后我必须开始执行并最后等待闩锁。

public FailSafeFuture execute(Execution execution,long timeout,TimeUnit timeoutUnit) {
    //Step 1
    final WaitingFailSafeFuture future = new WaitingFailSafeFuture();
    final CountDownLatch countDownLatch = new CountDownLatch(1);
    final PendingExecution pendingExecution = new PendingExecution(future, countDownLatch);
    final String id = execution.getId();
    pendingExecutions.put(id, pendingExecution); //ConcurrentHashMap shared with Bus

    //Step 2
    execution.execute();

    //Step 3
    final boolean awaitSuccessfull = countDownLatch.await(timeout, timeoutUnit);

    //...

    return future;
}

所以问题是:编译器可以对这 3 个步骤重新排序吗?据我了解,只有步骤1和步骤3形成了发生之前的关系。因此理论上,第 2 步可以由编译器自由移动。是否可以将步骤 2 移到等待后面,从而使代码无效?

后续问题:用共享对象上的等待/通知组合替换 CountDownLatch 是否可以解决问题而无需进一步同步(当然不考虑超时)

最佳答案

如果最终结果保持不变(就编译器的认为而言),则可能会发生指令重新排序,并且如果涉及多个线程,则可能需要额外的同步(因为编译器不知道其他线程可能期望特定的顺序) .

在单个线程中,如您的示例所示,所有步骤彼此之间都具有 happens-before 关系。偶if the compiler could reorder这些方法调用,最终结果需要相同(在 await() 之前调用 execute())。由于 await() 涉及同步,因此 execute() 不可能以某种方式落后于它,除非您使用的是 buggy 疯狂的实现。

countDown()await() 之间的 happens-before 关系确保 PendingExecution 代码发生在代码执行await()之前。所以显示的代码没有任何问题。

您应该始终更喜欢java.util.concurrent类而不是wait/notify,因为它们更易于使用并提供更多功能。

关于Java - CountDownLatch.await() 可以由编译器重新排序吗,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58605992/

相关文章:

java - 非法转义字符 "\("?

Java,隐式调用重写方法

c# - 实现无锁队列(用于 Logger 组件)

java - 适合 Java 事件监听器的集合类

C#按时间同步2个不同类型的列表

java - Postgresql 锁定多个用户的共享表

java - 以管理员身份运行 Alfresco Java 代码

java - 如何让线程等待,直到另一个线程完成该方法执行

java - 同步线程

synchronization - 使用 perforcesync -p 选项有什么优点?