22
33import java .util .concurrent .Callable ;
44
5+ /**
6+ * <p>
7+ * This application demonstrates the async method invocation pattern. Key parts of the pattern are
8+ * <code>AsyncResult</code> which is an intermediate container for an asynchronously evaluated value,
9+ * <code>AsyncCallback</code> which can be provided to be executed on task completion and
10+ * <code>AsyncExecutor</code> that manages the execution of the async tasks.
11+ * </p>
12+ * <p>
13+ * The main method shows example flow of async invocations. The main thread starts multiple tasks with
14+ * variable durations and then continues its own work. When the main thread has done it's job it collects
15+ * the results of the async tasks. Two of the tasks are handled with callbacks, meaning the callbacks are
16+ * executed immediately when the tasks complete.
17+ * </p>
18+ * <p>
19+ * Noteworthy difference of thread usage between the async results and callbacks is that the async results
20+ * are collected in the main thread but the callbacks are executed within the worker threads. This should be
21+ * noted when working with thread pools.
22+ * </p>
23+ * <p>
24+ * Java provides its own implementations of async method invocation pattern. FutureTask, CompletableFuture
25+ * and ExecutorService are the real world implementations of this pattern. But due to the nature of parallel
26+ * programming, the implementations are not trivial. This example does not take all possible scenarios into
27+ * account but rather provides a simple version that helps to understand the pattern.
28+ * </p>
29+ *
30+ * @see AsyncResult
31+ * @see AsyncCallback
32+ * @see AsyncExecutor
33+ *
34+ * @see java.util.concurrent.FutureTask
35+ * @see java.util.concurrent.CompletableFuture
36+ * @see java.util.concurrent.ExecutorService
37+ */
538public class App {
639
740 public static void main (String [] args ) throws Exception {
41+ // construct a new executor that will run async tasks
842 AsyncExecutor executor = new ThreadAsyncExecutor ();
43+
44+ // start few async tasks with varying processing times, two last with callback handlers
945 AsyncResult <Integer > asyncResult1 = executor .startProcess (lazyval (10 , 500 ));
1046 AsyncResult <String > asyncResult2 = executor .startProcess (lazyval ("test" , 300 ));
1147 AsyncResult <Long > asyncResult3 = executor .startProcess (lazyval (50L , 700 ));
1248 AsyncResult <Integer > asyncResult4 = executor .startProcess (lazyval (20 , 400 ), callback ("Callback result 4" ));
1349 AsyncResult <String > asyncResult5 = executor .startProcess (lazyval ("callback" , 600 ), callback ("Callback result 5" ));
1450
51+ // emulate processing in the current thread while async tasks are running in their own threads
1552 Thread .sleep (350 ); // Oh boy I'm working hard here
1653 log ("Some hard work done" );
1754
55+ // wait for completion of the tasks
1856 Integer result1 = executor .endProcess (asyncResult1 );
1957 String result2 = executor .endProcess (asyncResult2 );
2058 Long result3 = executor .endProcess (asyncResult3 );
2159 asyncResult4 .await ();
2260 asyncResult5 .await ();
2361
62+ // log the results of the tasks, callbacks log immediately when complete
2463 log ("Result 1: " + result1 );
2564 log ("Result 2: " + result2 );
2665 log ("Result 3: " + result3 );
2766 }
2867
68+ /**
69+ * Creates a callable that lazily evaluates to given value with artificial delay.
70+ *
71+ * @param value value to evaluate
72+ * @param delayMillis artificial delay in milliseconds
73+ * @return new callable for lazy evaluation
74+ */
2975 private static <T > Callable <T > lazyval (T value , long delayMillis ) {
3076 return () -> {
3177 Thread .sleep (delayMillis );
@@ -34,6 +80,12 @@ private static <T> Callable<T> lazyval(T value, long delayMillis) {
3480 };
3581 }
3682
83+ /**
84+ * Creates a simple callback that logs the complete status of the async result.
85+ *
86+ * @param name callback name
87+ * @return new async callback
88+ */
3789 private static <T > AsyncCallback <T > callback (String name ) {
3890 return (value , ex ) -> {
3991 if (ex .isPresent ()) {
0 commit comments