X Tutup
Skip to content

Commit 3e8ef01

Browse files
author
Tapio Rautonen
committed
iluwatar#68: Implementation of Async Method Invocation pattern
1 parent d3642cc commit 3e8ef01

File tree

8 files changed

+218
-0
lines changed

8 files changed

+218
-0
lines changed

async-method-invocation/pom.xml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?xml version="1.0"?>
2+
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
4+
<modelVersion>4.0.0</modelVersion>
5+
<parent>
6+
<groupId>com.iluwatar</groupId>
7+
<artifactId>java-design-patterns</artifactId>
8+
<version>1.3.0</version>
9+
</parent>
10+
<artifactId>async-method-invocation</artifactId>
11+
<dependencies>
12+
<dependency>
13+
<groupId>junit</groupId>
14+
<artifactId>junit</artifactId>
15+
<scope>test</scope>
16+
</dependency>
17+
</dependencies>
18+
</project>
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package com.iluwatar.async.method.invocation;
2+
3+
import java.util.concurrent.Callable;
4+
5+
public class App {
6+
7+
public static void main(String[] args) throws Exception {
8+
AsyncExecutor executor = new ThreadAsyncExecutor();
9+
AsyncResult<Integer> asyncResult1 = executor.startProcess(lazyval(10, 500));
10+
AsyncResult<String> asyncResult2 = executor.startProcess(lazyval("test", 300));
11+
AsyncResult<Long> asyncResult3 = executor.startProcess(lazyval(50L, 700));
12+
AsyncResult<Integer> asyncResult4 = executor.startProcess(lazyval(20, 400), callback("Callback result 4"));
13+
AsyncResult<String> asyncResult5 = executor.startProcess(lazyval("callback", 600), callback("Callback result 5"));
14+
15+
Thread.sleep(350); // Oh boy I'm working hard here
16+
log("Some hard work done");
17+
18+
Integer result1 = executor.endProcess(asyncResult1);
19+
String result2 = executor.endProcess(asyncResult2);
20+
Long result3 = executor.endProcess(asyncResult3);
21+
asyncResult4.await();
22+
asyncResult5.await();
23+
24+
log("Result 1: " + result1);
25+
log("Result 2: " + result2);
26+
log("Result 3: " + result3);
27+
}
28+
29+
private static <T> Callable<T> lazyval(T value, long delayMillis) {
30+
return () -> {
31+
Thread.sleep(delayMillis);
32+
log("Task completed with: " + value);
33+
return value;
34+
};
35+
}
36+
37+
private static <T> AsyncCallback<T> callback(String name) {
38+
return (value, ex) -> {
39+
if (ex.isPresent()) {
40+
log(name + " failed: " + ex.map(Exception::getMessage).orElse(""));
41+
} else {
42+
log(name + ": " + value);
43+
}
44+
};
45+
}
46+
47+
private static void log(String msg) {
48+
System.out.println(String.format("[%1$-10s] - %2$s", Thread.currentThread().getName(), msg));
49+
}
50+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package com.iluwatar.async.method.invocation;
2+
3+
import java.util.Optional;
4+
5+
public interface AsyncCallback<T> {
6+
7+
void onComplete(T value, Optional<Exception> ex);
8+
9+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package com.iluwatar.async.method.invocation;
2+
3+
import java.util.concurrent.Callable;
4+
import java.util.concurrent.ExecutionException;
5+
6+
public interface AsyncExecutor {
7+
8+
<T> AsyncResult<T> startProcess(Callable<T> task);
9+
10+
<T> AsyncResult<T> startProcess(Callable<T> task, AsyncCallback<T> callback);
11+
12+
<T> T endProcess(AsyncResult<T> asyncResult) throws ExecutionException, InterruptedException;
13+
14+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package com.iluwatar.async.method.invocation;
2+
3+
import java.util.concurrent.ExecutionException;
4+
5+
public interface AsyncResult<T> {
6+
7+
boolean isCompleted();
8+
9+
T getValue() throws ExecutionException;
10+
11+
void await() throws InterruptedException;
12+
}
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
package com.iluwatar.async.method.invocation;
2+
3+
import java.util.Optional;
4+
import java.util.concurrent.Callable;
5+
import java.util.concurrent.ExecutionException;
6+
import java.util.concurrent.atomic.AtomicInteger;
7+
8+
public class ThreadAsyncExecutor implements AsyncExecutor {
9+
10+
private final AtomicInteger idx = new AtomicInteger(0);
11+
12+
@Override
13+
public <T> AsyncResult<T> startProcess(Callable<T> task) {
14+
return startProcess(task, null);
15+
}
16+
17+
@Override
18+
public <T> AsyncResult<T> startProcess(Callable<T> task, AsyncCallback<T> callback) {
19+
CompletableResult<T> result = new CompletableResult<>(callback);
20+
new Thread(() -> {
21+
try {
22+
result.setValue(task.call());
23+
} catch (Exception ex) {
24+
result.setException(ex);
25+
}
26+
}, "executor-" + idx.incrementAndGet()).start();
27+
return result;
28+
}
29+
30+
@Override
31+
public <T> T endProcess(AsyncResult<T> asyncResult) throws ExecutionException, InterruptedException {
32+
if (asyncResult.isCompleted()) {
33+
return asyncResult.getValue();
34+
} else {
35+
asyncResult.await();
36+
return asyncResult.getValue();
37+
}
38+
}
39+
40+
private static class CompletableResult<T> implements AsyncResult<T> {
41+
42+
static final int RUNNING = 1;
43+
static final int FAILED = 2;
44+
static final int COMPLETED = 3;
45+
46+
final Object lock;
47+
final Optional<AsyncCallback<T>> callback;
48+
49+
volatile int state = RUNNING;
50+
T value;
51+
Exception exception;
52+
53+
CompletableResult(AsyncCallback<T> callback) {
54+
this.lock = new Object();
55+
this.callback = Optional.ofNullable(callback);
56+
}
57+
58+
void setValue(T value) {
59+
this.value = value;
60+
this.state = COMPLETED;
61+
this.callback.ifPresent(ac -> ac.onComplete(value, Optional.<Exception>empty()));
62+
synchronized (lock) {
63+
lock.notifyAll();
64+
}
65+
}
66+
67+
void setException(Exception exception) {
68+
this.exception = exception;
69+
this.state = FAILED;
70+
this.callback.ifPresent(ac -> ac.onComplete(null, Optional.of(exception)));
71+
synchronized (lock) {
72+
lock.notifyAll();
73+
}
74+
}
75+
76+
@Override
77+
public boolean isCompleted() {
78+
return (state > RUNNING);
79+
}
80+
81+
@Override
82+
public T getValue() throws ExecutionException {
83+
if (state == COMPLETED) {
84+
return value;
85+
} else if (state == FAILED) {
86+
throw new ExecutionException(exception);
87+
} else {
88+
throw new IllegalStateException("Execution not completed yet");
89+
}
90+
}
91+
92+
@Override
93+
public void await() throws InterruptedException {
94+
synchronized (lock) {
95+
if (!isCompleted()) {
96+
lock.wait();
97+
}
98+
}
99+
}
100+
}
101+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.iluwatar.async.method.invocation;
2+
3+
import org.junit.Test;
4+
5+
public class AppTest {
6+
7+
@Test
8+
public void test() throws Exception {
9+
String[] args = {};
10+
App.main(args);
11+
}
12+
13+
}

pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171
<module>naked-objects</module>
7272
<module>front-controller</module>
7373
<module>repository</module>
74+
<module>async-method-invocation</module>
7475
</modules>
7576

7677
<dependencyManagement>

0 commit comments

Comments
 (0)
X Tutup