The way we use Futures in our async code is unnecessarily complicated. AsyncTaskManager (in the original thread) creates a Future which the caller can wait on, but when an @Async method returns a Future, the invoked method (in the async thread) also has to create a Future before returning, and AsyncTaskManager (also in the async thread) immediately copies the results of that Future to the caller's Future. The use of extra Futures is confusing and error-prone. (EDIT: mainly because we sometimes pass in an AsyncTaskHandle with its own Future.)
I suggest AsyncTaskHandle should get its AsyncTaskResult (Future) when it is created (perhaps with the option of passing one in), with the method setFutureResult to be removed. (EDIT: done as part of ZNTA-1302.)
Any @Async method which currently returns Future<Void> should probably accept an AsyncTaskHandle parameter, provide its results directly to the handle's Future, and simply return void. Any @Async method which accepts an AsyncTaskHandle parameter should provide its results directly to that handle's Future and simply return void, not a Future. This avoids the confusion about which Future is the "real" one if the method were to return a different Future.
We would also need AsyncMethodInterceptor/AsyncTaskManager to ensure that the future is "done" one way or another when the invoked method returns (in case it failed to set a result). This should probably be an option, in case the @Async method wants to pass work (and the AsyncTaskHandle) off to another async process without tying up the thread.
For @Async methods which have no AsyncTaskHandle parameter, AsyncMethodInterceptor can create the AsyncTaskResult (Future) and pass it to the async thread to be completed when the invoked method returns.
EDIT: it might be good to replace AsyncTaskResult with javax.ejb.AsyncResult, just for consistency with Java EE's async framework. See also http://jdevelopment.nl/cdi-based-asynchronous-alternative/ for another CDI Async implementation.