Java has a Thread class from the beginning, but instantiation was heavy and subtle.
Executor was introduced from JDK5, making it easier to do WorkerThread-like things, and the number of Lock-type classes has increased, making it more convenient. In addition, the introduction of Future has made it easier to receive processing results. However, if you call Future.get (), the call Thread will block, so you have to write something that is not essential, such as doing it with another Thread.
Completable Future was introduced from Java8, and it seems that more complicated Thread processing can be performed, so I will investigate it.
I don't think you can understand it unless you understand Function, Consumer, and Supplier, which were also introduced in Java 8. I wrote an article below, so please refer to it. Investigation of Function, Consumer, Supplier, Predicate of Java8
Since it is the Supplier that returns a certain value and the Consumer that receives and processes the value, combine the two.
CompletableFuture.supplyAsync (Supplier) returns an instance of CompletableFuture while processing the Supplier asynchronously. In CompletableFuture.thenAcceptAsync (Consumer), when the processing of CompletableFuture instance is completed, pass the return value and execute Consumer processing.
public void SupplyAndConsume() {
Supplier<Integer> initValueSupplier = () -> 100;
Consumer<Integer> valueConsumer = value -> System.out.println(value);
CompletableFuture<Void> future =
CompletableFuture.supplyAsync(initValueSupplier)
.thenAcceptAsync(valueConsumer);
}
Processing result
100
It is the Supplier that returns a certain value, the Function that converts it, and the Consumer that receives it and processes it.
Basically the same as the previous pattern, but with CompletableFuture.thenApplyAsync (Function), execute the Function processing while passing the value of the result of CompletableFuture.
public void SupplyAndExecuteAndConsume() {
Supplier<Integer> initValueSupplier = () -> 100;
Function<Integer, Integer> multiply = value -> value * 2;
Consumer<Integer> valueConsumer = value -> System.out.println(value);
CompletableFuture<Void> future =
CompletableFuture.supplyAsync(initValueSupplier)
.thenApplyAsync(multiply)
.thenAcceptAsync(valueConsumer);
}
Processing result
200
Returns the result processed by Supplier and processes using the value received by Consumer. CompletableFuture.acceptEitherAsync (CompletableFuture, Consumer) can be used to perform Consumer processing using the one that gives the result first.
public void RaceAndConsume() {
Supplier<Integer> initValueSupplier = () -> 100;
Supplier<Integer> anotherValueSupplier = () -> 200;
Consumer<Integer> valueConsumer = value -> System.out.println(value);
CompletableFuture<Integer> future1 =
CompletableFuture.supplyAsync(initValueSupplier);
CompletableFuture<Integer> future2 =
CompletableFuture.supplyAsync(anotherValueSupplier);
future1.acceptEitherAsync(future2, valueConsumer);
}
100 or 200
public void RaceAndConsume() {
Supplier<Integer> initValueSupplier = () -> 100;
Supplier<Integer> anotherValueSupplier = () -> 200;
Function<Integer, Integer> multiply = value -> value * 2;
Consumer<Integer> valueConsumer = value -> System.out.println(value);
CompletableFuture<Integer> future1 =
CompletableFuture.supplyAsync(initValueSupplier);
CompletableFuture<Integer> future2 =
CompletableFuture.supplyAsync(anotherValueSupplier);
future1.applyToEitherAsync(future2, multiply)
.thenAcceptAsync(valueConsumer);
}
200 or 400
Explanation of synchronized and typical error example I wrote, so please check it out as well. Experience shows that about 70% of people are wrong.