I have to invoke an operation on a different system. The other system is highly concurrent and distributed. Therefore I integrate it over a MessageBus. One implementation is required to let the caller wait until the result got received on the bus or the timeout expires. The implementation consists of three steps: First I have to pack the future and the CountDownLatch, which is released once the result is received, into a ConcurrentHashMap. This Map is shared with the component listening on the MessageBus. Then I have to start the execution and finally wait on the latch.
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;
}
So the question is: Can those 3 Steps be reordered by the compiler? As far as I understand, only Step 1 and Step 3 form a happens-before relationship. So in theory step 2 could be freely moved by the compiler. Could step 2 even be moved behind the await and therefore would invalidate the code?
Follow-up question: Would replacing the CountDownLatch with a wait/notify combination on a shared object solve the problem without further synchronization (leaving out the timeout of course)