si sta modellando le dipendenze di stadi di completamento da loro concatenamento. Se si concatenano due azioni A
e B
a un'altra azione C
, si definiscono i rapporti A → C
e B → C
, ma nessuna relazione tra A
e B
e, pertanto, non v'è alcuna relazione, tra cui nessun rapporto ordinamento, tra di loro, in altre parole, è possibile 't anche per scontato che uno verrà eseguito dopo l'altro, vale a dire
CompletableFuture<String> base=CompletableFuture.supplyAsync(() -> {
LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(2));
return "source";
});
base.thenAccept(s -> {
System.out.println("entered first consumer in "+Thread.currentThread());
LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(1));
System.out.println("leaving first consumer");
});
LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(2));
base.thenAccept(s -> {
System.out.println("entered second consumer in "+Thread.currentThread());
LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(1));
System.out.println("leaving second consumer");
});
sarà molto probabile che qualcosa di stampa come
entered first consumer in Thread[ForkJoinPool.commonPool-worker-1,5,main]
entered second consumer in Thread[main,5,main]
leaving second consumer
leaving first consumer
anche se, naturalmente, non v'è alcuna garanzia su di esso.
Per imporre la vostra dipendenza tra i due consumatori, si deve a catena in modo appropriato, per esempio
CompletableFuture<String> base=CompletableFuture.supplyAsync(() -> {
LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(2));
return "source";
});
CompletableFuture<Void> next = base.thenAccept(s -> {
System.out.println("entered first consumer in "+Thread.currentThread());
LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(1));
System.out.println("leaving first consumer");
});
LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(2));
base.thenAcceptBoth(next, (s,ignored) -> {
System.out.println("entered second consumer in "+Thread.currentThread());
LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(1));
System.out.println("leaving second consumer");
}).join();
Qui, il secondo consumatore è incatenato al base
e next
, per ricevere il risultato da base
, ma dipendono dal completamento next
s'(che normalmente non richiederebbe se non c'è risultato di passare, forse vuoi ripensare il tuo design, se hai uno scenario del genere).
In alternativa, è possibile convertire il primo Consumer
ad un Function
che passa attraverso il valore, in modo da poter concatenare via thenApply
, per consentire il concatenamento un'altra thenAccept
fase ad esso.
"thenAccept" significa che il primo "questo" CompletableFuture è stato completato e solo successivamente viene eseguita la funzione del parametro. –