Parallele Programmierung (3IB)
=> Grundlage: Hettel und Tran (2016, Kap. 15)
FutureCompletableFuture (Framework)
CompletableFuturex, y) mit gleichmäßiger Verteilung\[\frac{\mbox{Anzahl der Punkte innerhalb und auf dem Kreis}}{\mbox{Anzahl aller Punkte}} = \frac{\frac{\pi r^2}{4}}{r^2}\]
pi = 4.0 * in / (in + out)
in: Anzahl der Punkte innerhalb des Kreises (sqrt(x*x + y*y) <= 1)out: die restlichen, die außerhalb des Kreises liegen (sqrt(x*x + y*y) > 1)pp.08.01-ConcurrencyMonteCarloPiSeqFuture”pp.08.02-ConcurrencyMonteCarloPiFutureCompletableFuturecommonPoolpp.08.03-CommonPoolCompletableFutureFuture/Callable
Callable wird Input für nächstes CallableCallable ausgeführt wird:
commonPoolCompletableFutureFuture: read-only Container für zukünftiges Ergebnis (“Promise”)CompletionStage: triggert weitere VerarbeitungCompletionStage (Push-API)commonPoolExecutorcommonPoolCompletionStageCompletionStage (Push-API)CompletableFuturenach Hettel und Tran (2016, 240) (Änderungen: Annotationen und supplyAsync statt applyAsync in Start-API)
static CompletableFuture<Integer> calculateAsync() {
var result = new CompletableFuture<Integer>();
ForkJoinPool.commonPool().submit(() -> {
try {
var res = /* aufwändige Berechnung, Ergebnis z.B. */ 42;
result.complete(res);
} catch (Exception ex) {
result.completeExceptionally(ex);
}
});
return result;
}
public static void main(String... args) {
var cf = calculateAsync();
try {
System.out.println(cf.get());
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} catch (ExecutionException e) {
System.err.print(e);
}
}import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.function.Supplier;
public class SimpleCompletableFuture {
static class Task implements Supplier<Integer> {
@Override
public Integer get() {
return /* aufwändige Berechnung, Ergebnis z.B. */ 42;
}
}
public static void main(String... args)
throws InterruptedException, ExecutionException {
var future = CompletableFuture.supplyAsync(new Task());
System.out.println(future.get());
}
}import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
public class SimpleCompletableFuture {
public static void main(String... args)
throws InterruptedException, ExecutionException {
var future = CompletableFuture.supplyAsync(() -> {
return /* aufwändige Berechnung, Ergebnis z.B. */ 42;
});
System.out.println(future.get());
}
}CompletableFuture– lineare Ketten und Verzweigungen –
Für jedes thenApplyAsync und theAcceptAsync wird ggf. ein eigener Thread aus dem Threadpool benutzt.

Hettel und Tran (2016, 252) (modifiziert)
public class Service {
static User getUser(int userId) { ... }
static Profile getProfile(User user) { ... }
static AccessRight getAccessRight(Profile profile) { ... }
}
CompletableFuture<Void> cf = CompletableFuture
.supplyAsync(() -> Service.getUser(42))
.thenApplyAsync((user) -> Service.getProfile(user))
.thenApplyAsync((profile) -> Service.getAccessRight(profile))
.thenAcceptAsync((access) -> System.out.println(access));
cf.join(); // wartet auf das Ende der Berechnung von cf,
// hier also auf die erfolgte Ausgabepublic class Service {
public static User getUser(int userId) { ... }
public static Profile getProfile(User user) { ... }
public static AccessRight getAccessRight(Profile profile) { ... }
}
CompletableFuture<Void> cf = CompletableFuture
.supplyAsync(() -> T)
.thenApplyAsync((T t) -> U)
.thenApplyAsync((U u) -> V)
.thenAcceptAsync((V v) -> Void); // void (kleingeschrieben)
// ist in Java kein Typ, sondern ein Schlüsselwort in Signaturen
cf.join();| Methode | Task-Typ | Resultat | ||
|---|---|---|---|---|
thenRun |
Runnable: () -> void |
CompletableFuture<Void> |
||
thenAccept |
Consumer: (T) -> void |
CompletableFuture<Void> |
||
thenApply |
Function: (T) -> U |
CompletableFuture<U> |
CompletableFuture-Task schon fertig ist, wird der nächste Task im Aufrufer-Thread ausgeführt.CompletableFuture-Task noch nicht fertig ist, wird der nächste Task anschließend im Thread des vorigen Tasks ausgeführt.
T: String
'4711'U: Integer
4V: Boolean
false
Hettel und Tran (2016, 252)
Hettel und Tran (2016, 252)
Methoden zur Vereinigung von Abläufen. “CF” steht für CompletableFuture und “CS” für CompletionStage
thenCombine (Verrechnen)
T: Integer
47U: String
'11'V: String
'4711'
Hettel und Tran (2016, 253)
applyToEither (“ODER”)
T: Integer
47U: Integer
11V: Boolean
true oder false
Hettel und Tran (2016, 255)
Hettel und Tran (2016, 257) (modifiziert)
CompletableFuture.allOf( // alle müssen beendet werden
CompletableFuture.runAsync( () -> { /*...*/ } ),
CompletableFuture.runAsync( () -> { /*...*/ } ),
CompletableFuture.runAsync( () -> { /*...*/ } )
).thenAccept((Void) -> System.out.println("done") );
CompletableFuture.anyOf( // das frühest fertige
CompletableFuture.supplyAsync( () -> { /*...*/ } ),
CompletableFuture.supplyAsync( () -> { /*...*/ } ),
CompletableFuture.supplyAsync( () -> { /*...*/ } )
).thenAccept((first) -> System.out.println(first));var cf = CompletableFuture
.supplyAsync(() -> 42)
.thenApplyAsync(r -> r / 0)
.thenApplyAsync(r -> r * r)
.thenApplyAsync(r -> r > 0)
.handle((r, th) -> {
if (r != null) {
System.out.println("Resultat: " + r);
return r;
} else {
System.err.println("error: " + th);
return false;
}
});
System.out.println(cf.join());
Hettel und Tran (2016, 258) (modifiziert)

Hettel und Tran (2016, 258) (modifiziert)
CompletableFuture”pp.08.04-ConcurrencyMonteCarloPiCF