Я должен вызвать операцию в другой системе. Другая система очень параллельна и распределена. Поэтому я интегрирую его через MessageBus. Одна реализация должна позволить вызывающей стороне подождать, пока не будет получен результат, полученный на шине, или истечет время ожидания. Реализация состоит из трех этапов: сначала мне нужно упаковать будущее и 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 комбинацией ожидания / уведомления на общем объекте решить проблему без дальнейшей синхронизации (исключаятайм-аут конечно)