Skip to content

Commit 5cc83b8

Browse files
author
Tapio Rautonen
committed
iluwatar#68: Javadocs.
1 parent 3e8ef01 commit 5cc83b8

File tree

5 files changed

+122
-0
lines changed

5 files changed

+122
-0
lines changed

async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/App.java

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,30 +2,76 @@
22

33
import 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+
*/
538
public 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()) {

async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/AsyncCallback.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@
44

55
public interface AsyncCallback<T> {
66

7+
/**
8+
* Complete handler which is executed when async task is completed or fails execution.
9+
*
10+
* @param value the evaluated value from async task, undefined when execution fails
11+
* @param ex empty value if execution succeeds, some exception if executions fails
12+
*/
713
void onComplete(T value, Optional<Exception> ex);
814

915
}

async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/AsyncExecutor.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,33 @@
55

66
public interface AsyncExecutor {
77

8+
/**
9+
* Starts processing of an async task. Returns immediately with async result.
10+
*
11+
* @param task task to be executed asynchronously
12+
* @return async result for the task
13+
*/
814
<T> AsyncResult<T> startProcess(Callable<T> task);
915

16+
/**
17+
* Starts processing of an async task. Returns immediately with async result. Executes callback
18+
* when the task is completed.
19+
*
20+
* @param task task to be executed asynchronously
21+
* @param callback callback to be executed on task completion
22+
* @return async result for the task
23+
*/
1024
<T> AsyncResult<T> startProcess(Callable<T> task, AsyncCallback<T> callback);
1125

26+
/**
27+
* Ends processing of an async task. Blocks the current thread if necessary and returns the
28+
* evaluated value of the completed task.
29+
*
30+
* @param asyncResult async result of a task
31+
* @return evaluated value of the completed task
32+
* @throws ExecutionException if execution has failed, containing the root cause
33+
* @throws InterruptedException if the execution is interrupted
34+
*/
1235
<T> T endProcess(AsyncResult<T> asyncResult) throws ExecutionException, InterruptedException;
1336

1437
}

async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/AsyncResult.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,26 @@
44

55
public interface AsyncResult<T> {
66

7+
/**
8+
* Status of the async task execution.
9+
*
10+
* @return <code>true</code> if execution is completed or failed
11+
*/
712
boolean isCompleted();
813

14+
/**
15+
* Gets the value of completed async task.
16+
*
17+
* @return evaluated value or throws ExecutionException if execution has failed
18+
* @throws ExecutionException if execution has failed, containing the root cause
19+
* @throws IllegalStateException if execution is not completed
20+
*/
921
T getValue() throws ExecutionException;
1022

23+
/**
24+
* Blocks the current thread until the async task is completed.
25+
*
26+
* @throws InterruptedException if the execution is interrupted
27+
*/
1128
void await() throws InterruptedException;
1229
}

async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/ThreadAsyncExecutor.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,12 @@
55
import java.util.concurrent.ExecutionException;
66
import java.util.concurrent.atomic.AtomicInteger;
77

8+
/**
9+
* Implementation of async executor that creates a new thread for every task.
10+
*/
811
public class ThreadAsyncExecutor implements AsyncExecutor {
912

13+
/** Index for thread naming */
1014
private final AtomicInteger idx = new AtomicInteger(0);
1115

1216
@Override
@@ -37,6 +41,14 @@ public <T> T endProcess(AsyncResult<T> asyncResult) throws ExecutionException, I
3741
}
3842
}
3943

44+
/**
45+
* Simple implementation of async result that allows completing it successfully with a value
46+
* or exceptionally with an exception. A really simplified version from its real life cousins
47+
* FutureTask and CompletableFuture.
48+
*
49+
* @see java.util.concurrent.FutureTask
50+
* @see java.util.concurrent.CompletableFuture
51+
*/
4052
private static class CompletableResult<T> implements AsyncResult<T> {
4153

4254
static final int RUNNING = 1;
@@ -55,6 +67,12 @@ private static class CompletableResult<T> implements AsyncResult<T> {
5567
this.callback = Optional.ofNullable(callback);
5668
}
5769

70+
/**
71+
* Sets the value from successful execution and executes callback if available. Notifies
72+
* any thread waiting for completion.
73+
*
74+
* @param value value of the evaluated task
75+
*/
5876
void setValue(T value) {
5977
this.value = value;
6078
this.state = COMPLETED;
@@ -64,6 +82,12 @@ void setValue(T value) {
6482
}
6583
}
6684

85+
/**
86+
* Sets the exception from failed execution and executes callback if available. Notifies
87+
* any thread waiting for completion.
88+
*
89+
* @param exception exception of the failed task
90+
*/
6791
void setException(Exception exception) {
6892
this.exception = exception;
6993
this.state = FAILED;

0 commit comments

Comments
 (0)