#68: Implementation of Async Method Invocation pattern
This commit is contained in:
parent
d3642cc94c
commit
3e8ef01288
18
async-method-invocation/pom.xml
Normal file
18
async-method-invocation/pom.xml
Normal file
@ -0,0 +1,18 @@
|
||||
<?xml version="1.0"?>
|
||||
<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"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<version>1.3.0</version>
|
||||
</parent>
|
||||
<artifactId>async-method-invocation</artifactId>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
@ -0,0 +1,50 @@
|
||||
package com.iluwatar.async.method.invocation;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
public class App {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
AsyncExecutor executor = new ThreadAsyncExecutor();
|
||||
AsyncResult<Integer> asyncResult1 = executor.startProcess(lazyval(10, 500));
|
||||
AsyncResult<String> asyncResult2 = executor.startProcess(lazyval("test", 300));
|
||||
AsyncResult<Long> asyncResult3 = executor.startProcess(lazyval(50L, 700));
|
||||
AsyncResult<Integer> asyncResult4 = executor.startProcess(lazyval(20, 400), callback("Callback result 4"));
|
||||
AsyncResult<String> asyncResult5 = executor.startProcess(lazyval("callback", 600), callback("Callback result 5"));
|
||||
|
||||
Thread.sleep(350); // Oh boy I'm working hard here
|
||||
log("Some hard work done");
|
||||
|
||||
Integer result1 = executor.endProcess(asyncResult1);
|
||||
String result2 = executor.endProcess(asyncResult2);
|
||||
Long result3 = executor.endProcess(asyncResult3);
|
||||
asyncResult4.await();
|
||||
asyncResult5.await();
|
||||
|
||||
log("Result 1: " + result1);
|
||||
log("Result 2: " + result2);
|
||||
log("Result 3: " + result3);
|
||||
}
|
||||
|
||||
private static <T> Callable<T> lazyval(T value, long delayMillis) {
|
||||
return () -> {
|
||||
Thread.sleep(delayMillis);
|
||||
log("Task completed with: " + value);
|
||||
return value;
|
||||
};
|
||||
}
|
||||
|
||||
private static <T> AsyncCallback<T> callback(String name) {
|
||||
return (value, ex) -> {
|
||||
if (ex.isPresent()) {
|
||||
log(name + " failed: " + ex.map(Exception::getMessage).orElse(""));
|
||||
} else {
|
||||
log(name + ": " + value);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static void log(String msg) {
|
||||
System.out.println(String.format("[%1$-10s] - %2$s", Thread.currentThread().getName(), msg));
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package com.iluwatar.async.method.invocation;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public interface AsyncCallback<T> {
|
||||
|
||||
void onComplete(T value, Optional<Exception> ex);
|
||||
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package com.iluwatar.async.method.invocation;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
public interface AsyncExecutor {
|
||||
|
||||
<T> AsyncResult<T> startProcess(Callable<T> task);
|
||||
|
||||
<T> AsyncResult<T> startProcess(Callable<T> task, AsyncCallback<T> callback);
|
||||
|
||||
<T> T endProcess(AsyncResult<T> asyncResult) throws ExecutionException, InterruptedException;
|
||||
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package com.iluwatar.async.method.invocation;
|
||||
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
public interface AsyncResult<T> {
|
||||
|
||||
boolean isCompleted();
|
||||
|
||||
T getValue() throws ExecutionException;
|
||||
|
||||
void await() throws InterruptedException;
|
||||
}
|
@ -0,0 +1,101 @@
|
||||
package com.iluwatar.async.method.invocation;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
public class ThreadAsyncExecutor implements AsyncExecutor {
|
||||
|
||||
private final AtomicInteger idx = new AtomicInteger(0);
|
||||
|
||||
@Override
|
||||
public <T> AsyncResult<T> startProcess(Callable<T> task) {
|
||||
return startProcess(task, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> AsyncResult<T> startProcess(Callable<T> task, AsyncCallback<T> callback) {
|
||||
CompletableResult<T> result = new CompletableResult<>(callback);
|
||||
new Thread(() -> {
|
||||
try {
|
||||
result.setValue(task.call());
|
||||
} catch (Exception ex) {
|
||||
result.setException(ex);
|
||||
}
|
||||
}, "executor-" + idx.incrementAndGet()).start();
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T endProcess(AsyncResult<T> asyncResult) throws ExecutionException, InterruptedException {
|
||||
if (asyncResult.isCompleted()) {
|
||||
return asyncResult.getValue();
|
||||
} else {
|
||||
asyncResult.await();
|
||||
return asyncResult.getValue();
|
||||
}
|
||||
}
|
||||
|
||||
private static class CompletableResult<T> implements AsyncResult<T> {
|
||||
|
||||
static final int RUNNING = 1;
|
||||
static final int FAILED = 2;
|
||||
static final int COMPLETED = 3;
|
||||
|
||||
final Object lock;
|
||||
final Optional<AsyncCallback<T>> callback;
|
||||
|
||||
volatile int state = RUNNING;
|
||||
T value;
|
||||
Exception exception;
|
||||
|
||||
CompletableResult(AsyncCallback<T> callback) {
|
||||
this.lock = new Object();
|
||||
this.callback = Optional.ofNullable(callback);
|
||||
}
|
||||
|
||||
void setValue(T value) {
|
||||
this.value = value;
|
||||
this.state = COMPLETED;
|
||||
this.callback.ifPresent(ac -> ac.onComplete(value, Optional.<Exception>empty()));
|
||||
synchronized (lock) {
|
||||
lock.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
void setException(Exception exception) {
|
||||
this.exception = exception;
|
||||
this.state = FAILED;
|
||||
this.callback.ifPresent(ac -> ac.onComplete(null, Optional.of(exception)));
|
||||
synchronized (lock) {
|
||||
lock.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCompleted() {
|
||||
return (state > RUNNING);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T getValue() throws ExecutionException {
|
||||
if (state == COMPLETED) {
|
||||
return value;
|
||||
} else if (state == FAILED) {
|
||||
throw new ExecutionException(exception);
|
||||
} else {
|
||||
throw new IllegalStateException("Execution not completed yet");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void await() throws InterruptedException {
|
||||
synchronized (lock) {
|
||||
if (!isCompleted()) {
|
||||
lock.wait();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package com.iluwatar.async.method.invocation;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class AppTest {
|
||||
|
||||
@Test
|
||||
public void test() throws Exception {
|
||||
String[] args = {};
|
||||
App.main(args);
|
||||
}
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user