Asynchronous callback completable future
Completable future is used for asynchronous programming in Java JDK1.8. Asynchrony usually means non blocking, which can make our task run separately in other threads separated from the main thread. Through callback, we can get the execution status, completion, exception and other information of asynchronous task in the main thread.
public class CompletableFuture<T> implements Future<T>, CompletionStage<T> //Two interfaces are implemented
Why use completable Future to make asynchronous calls instead of Future?
The main disadvantages of Future are as follows:
(1) Manual completion is not supported. I submitted a task, but the execution is too slow. I have obtained the task result through other paths. Now I can't notify the executing thread of the task result, so I must actively cancel or wait for it to complete
(2) Further non blocking calls are not supported. The get method of Future will block until the task is completed, but you want to execute additional tasks after obtaining the task. Because Future does not support callback functions, this function cannot be realized
(3) The execution result of Future is not supported by chain call. We want to continue to pass it to the next Future for processing, so as to form a chain pipline call, which cannot be realized in Future.
(4) Multiple Future merging is not supported. For example, we have 10 Future executing in parallel. We want to execute some functions after all Future runs, which can not be realized through Future.
(5) The api that does not support exception handling does not have any api for exception handling, so it is difficult to locate problems during asynchronous operation.
Completable future is optimized for the above
Chained call + lamda expression is still very comfortable
Asynchronous task with return value
-
There are with return value and without return value, and thread pool. (use the default thread pool if not used)
-
//From its own thread pool, the executor takes out a thread to execute CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(()->{ System.out.println(Thread.currentThread().getName()+" : completableFuture"); return 1024; },executor);); //Get the results with get System.out.println("main......end....." + completableFuture.get());
Callback when calculation is completed
whenComplete and whenCompleteAsync (asynchronous)
-
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> { System.out.println("Current thread:" + Thread.currentThread().getId()); int i = 10 / 0; System.out.println("Operation results:" + i); return i; }, executor).whenComplete((res,exception) -> { //Although the exception information can be obtained, the returned data cannot be modified System.out.println("The asynchronous task completed successfully...The result is:" + res + "The exception is:" + exception); })
exception handling
-
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> { System.out.println("Current thread:" + Thread.currentThread().getId()); int i = 10 / 0; System.out.println("Operation results:" + i); return i; }, executor).whenComplete((res,exception) -> { //Although the exception information can be obtained, the returned data cannot be modified System.out.println("The asynchronous task completed successfully...The result is:" + res + "The exception is:" + exception); }).exceptionally(throwable -> { //It can sense the exception and return the default value return 10; });
handle after method execution
-
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> { System.out.println("Current thread:" + Thread.currentThread().getId()); int i = 10 / 2; System.out.println("Operation results:" + i); return i; }, executor).handle((result,thr) -> { if (result != null) { return result * 2; } if (thr != null) { System.out.println("The asynchronous task completed successfully...The result is:" + result + "The exception is:" + thr); return 0; } return 0; }); //handle has three parameters, bifunction < T, U, R > t, return result U, exception r handler
Thread serialization
-
thenApply method: when a thread depends on another thread, it obtains the result returned by the previous task and returns the return value of the current task.
-
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> { System.out.println("Current thread:" + Thread.currentThread().getId()); int i = 10 / 2; System.out.println("Operation results:" + i); return i; }, executor).thenApplyAsync(res -> { System.out.println("Task 2 started..." + res); //Return value + accept last result return "Hello" + res; }, executor); System.out.println("main......end....." + future.get());
-
-
thenAccept method: consume the processing result. Receive the processing result of the task and consume it. No result is returned.
-
thenRun method: execute thenRun as long as the above task is completed. Only after processing the task, the execution result cannot be obtained and the subsequent operations of thenRun can be executed
Task combination
Both tasks must be completed to trigger the task.
The following AIPS have polymorphic methods, which are used in asynchronous xxasync or with asynchronous + thread pool
-
thenCombine: combine two futures, obtain the return results of the two futures, and return the return value of the current task
-
//Task 01 combined task 02 run after both tasks are completed future01.thenAcceptBothAsync(future02,(R1,R2)->{ System.out.println("Start task 3...The previous result was "+ R1 +"----" + R2); },executor);
-
-
Then accept both: combine the two future tasks, obtain the return results of the two future tasks, and then process the tasks without return value.
-
//Task 01 combined task 02 runs after both tasks are completed with a return value CompletableFuture<String> future = future01.thenCombineAsync(future02, (R1, R2) -> { System.out.println("Start task 3...The previous result was " + R1 + "----" + R2); return "new reslut"; }, executor); System.out.println(future.get());
-
-
runAfterBoth: combine two futures. You don't need to obtain the results of the future. You only need to process the task after the two futures process the task.
Two tasks are combined to complete one
When either of the two future tasks is completed, execute the task. The following AIPS have polymorphic methods, which are used in asynchronous xxasync or with asynchronous + thread pool
Like a hair on top
- applyToEither: when one of the two tasks is completed, get its return value, process the task and have a new return value.
- acceptEither: one of the two tasks is completed. Get its return value and process the task. There is no new return value.
- runAfterEither: one of the two tasks is completed. There is no need to obtain the future results, process the task, and there is no return value.
Multi task combination
-
allOf: wait for all tasks to complete
-
CompletableFuture<Void> allofFuture = CompletableFuture.allOf(future01, future02, completableFuture);
-
anyOf: as long as one task is completed