当前位置:网站首页>Multithreaded asynchronous orchestration
Multithreaded asynchronous orchestration
2022-07-07 10:30:00 【HGW689】
List of articles
As we all know Java Language native supports multithreading , There are four ways to implement multithreading :
- Inherit Thread Class and rewrite run Method to create a thread , The implementation is simple, but you can't inherit other classes ;
- Realization Runnable Interface and override run Method , Avoid the limitations of single inheritance , Programming is more flexible , Realize decoupling ;
- Realization Callable Interface and override call Method , Create thread . You can get the return value of the thread execution result , And throw an exception ;
- Use thread pool to create .
difference :
- The way 1 And way 2: The main process cannot get the operation result of the thread .
- The way 3: The main process can get the operation results of the thread , However, it is not conducive to controlling the thread resources in the server . This may cause the server to run out of resources .
- The way 4: Can control resources , The system performance is stable
First write a Demo Well :
public class ThreadTest {
// Currently, there are only one or two system pools , Each asynchronous task is submitted directly to the thread pool , Let him do it himself
public static ExecutorService service = Executors.newFixedThreadPool(10);
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println("main...start....");
/** * 1. Inherit Thread * Thread01 thread = new Thread01(); * thread.start(); * 2. Realization Runnable Interface * Runable01 runable01 = new Runable01(); * new Thread(runable01).start(); * 3. Realization Callable Interface + FutureTask ( You can get the results back , Can handle exceptions ) * FutureTask<Integer> futureTask = new FutureTask<>(new Callable01()); * new Thread(futureTask).start(); * // Blocking waits for the entire thread to complete execution , Get the return result * Integer integer = futureTask.get(); * 4. Thread pool * Submit tasks directly to the thread pool . * We'll be in the business code later , None of the above three ways to start threads .【 Hand over all multithreaded asynchronous tasks to the thread pool for execution 】 * difference : * 1、2 Can't get the return value ,3 Can get the return value * 1、2、3 Can't control resources * 4 Can control resources , The system performance is stable */
service.execute(new Runable01());
}
public static class Thread01 extends Thread {
@Override
public void run() {
System.out.println(" Current thread : " + Thread.currentThread().getId());
int i = 10/2;
System.out.println(" Running results :" + i);
}
}
public static class Runable01 implements Runnable {
@Override
public void run() {
System.out.println(" Current thread : " + Thread.currentThread().getId());
int i = 10/2;
System.out.println(" Running results :" + i);
}
}
public static class Callable01 implements Callable<Integer> {
@Override
public Integer call() throws Exception {
System.out.println(" Current thread : " + Thread.currentThread().getId());
int i = 10/2;
System.out.println(" Running results :" + i);
return i;
}
}
}
The first two implementation methods are not explained here .
1、Callable Interface
Realization Callable Interface and override call Method , Create thread . You can get the return value of the thread execution result , And throw an exception ;
- advantage :
- You can get the return value of task execution ;
- Through and with Future The combination of , We can make use of Future To track the results of asynchronous calculations .
Runbable and Callable The difference between ?
- Callable The prescribed method is call(),Runnable The prescribed method is run().
- Callable After the task is executed, it can return the value , and Runnable The task is not worth returning
- call Methods can throw exceptions ,run Method can not
- function Callable The mission can get a Future object , Represents the result of an asynchronous calculation . It provides a way to check if the calculation is complete , To wait for the calculation to complete , And retrieve the calculated results . adopt Future Object can understand task execution , The execution of the task can be cancelled , You can also get execution results .
Future Interface
- Future It's an interface , Represents the result of an asynchronous calculation . The method in the interface is used to check whether the calculation is completed 、 Wait for completion and get the result of the calculation .
- When the calculation is done , Only through get() Method to get the result ,get The method will block until the result is ready .
- If you want to cancel , So called cancel() Method . Other methods are used to determine whether the task is completed normally or cancelled .
- Once the calculation is done , Then this calculation cannot be cancelled .
FutureTask class
- FutureTask Class implements the RunnableFuture Interface , and RunnnableFuture Interface inherited Runnable and Future Interface , So FutureTask Is a task that provides the results of asynchronous computing .
- FutureTask Can be used to pack Callable perhaps Runnbale object . because FutureTask Realized Runnable Interface , therefore FutureTask Can also be submitted to Executor.
Callable How to execute
// FutureTask
FutureTask<Integer> futureTask1 = new FutureTask<>(new MyThread2());
new Thread(futureTask1,"BB").start();
System.out.println(futureTask1.get());
Of course, it can also be done Lambda Simplify (Callable It's a functional interface ):
// Lambda Simplify the expression
FutureTask<Integer> futureTask2 = new FutureTask<>(()->{
return 1024;
});
2、 Thread pool
Thread pool [ExecutorService]
Native :service.execute(new Runable01());
establish
- Executors
- new ThreadPoolExecutor()
Why do I need thread pools ?
- Avoid the consumption caused by thread creation and destruction
- Improve the response speed of the system
- Adjust the size of the number of threads according to the affordability of the system
Classification of thread pool
- newCachedThreadPool : Create a thread pool that can be reused for caching
- newFixedThreadPool : Create a thread pool that can reuse a fixed number of threads
- newSingleThreadExecutor : Create one using a single worker Thread Executor, Run the thread in a sessional queue . At most one thread can be executed in the thread pool , After that, the submitted thread will be queued to execute .
- newSingleThreadScheduledExecutor : Create a single thread executor , It can be scheduled to run a command after a given delay or to execute it periodically
- newScheduledThreadPool : Create a thread pool , It can be scheduled to run commands after a given delay or to execute them periodically
- newWorkStealingPool : Create a thread pool with parallel levels , The parallelism level determines the maximum number of threads executing at the same time , If the parallel level parameter is not passed , Will default to the current system's CPU Number .
Core parameters
- corePoolSize : Number of core threads ,[ Always exist , Unless set (allowCoreThreadTimeOut)], Number of threads ready after creation , Just wait to accept asynchronous tasks to execute
- maximumPoolSize : Maximum number of threads ; Control resources
- keepAliveTime : Survival time , If the current number of threads is greater than the number of core threads , As long as the thread is idle for more than the specified time (keepAliveTime), It will release threads outside the idle core thread (maximumPoolSize - corePoolSize).
- unit: Time unit , by keepAliveTime Specify the time unit
- BlockingWorkQueue : Blocking queues ; If there are many tasks , Threads are working , Put the current multiple tasks in the queue . As long as there are threads idle , Will go to the queue to take out new tasks and continue to execute
- ThreadFactory: Create a factory class for threads
- Handler: Refusal strategy , If the queue is full , According to the rejection policy we specify , Refuse to perform a task
- AbortPolicy( Termination strategy ):, Discarding the task , And throw an exception .(jdk The default policy )
- DiscardPolicy ( Discard strategy ): Discarding the task , Don't throw exceptions
- DiscardOldestPolicy( Abandoning the old strategy ): Discard the top task in the queue , Then perform the task again
- CallerRunsPolicy ( Caller policy ): Neither discard the task nor throw an exception , Instead, some tasks are rolled back to the caller , Let the caller execute it
Working process of thread pool ?
- Thread pool creation , Get ready corePoolSize( Number of core threads ) The thread of , Ready to receive the task .
- New tasks come in , use core The prepared idle thread executes
- If core thread is full , Put the incoming tasks into the blocking queue . Idle core It will block the queue to get the task execution .
- The blocking queue is full , Just open a new thread to execute , It can only drive up to maximumPoolSize Maximum number of core threads specified
- If the maximum number of threads is full , Leave it to the rejection strategy .
- If there are idle threads at the specified time KeepAliveTime in the future , Will release idle threads ( This refers to threads other than the core thread ).
2.1、 Configure thread pool
First step 、 Write a tool class to create thread pool
1、 Add thread pool property configuration class , And into the container
package com.atguigu.gulimall.product.config;
@ConfigurationProperties(prefix = "gulimall.thread")
@Component
@Data
public class ThreadPoolConfigProperties {
private Integer coreSize;
private Integer maxSize;
private Integer keepAliveTime;
}
Here you need to import a tool dependency , It's OK not to lead :
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
2、 add to Configuration of thread pool properties
stay gulimall-product Add the following configuration to the service :
# Configure thread pool
gulimall:
thread:
core-size: 20
max-size: 200
keep-alive-time: 10
3、 Thread pool configuration , Get the property value of the thread pool. Here, directly call the property configuration class corresponding to the configuration file
package com.atguigu.gulimall.product.config;
@Configuration
public class MyThreadConfig {
@Bean
public ThreadPoolExecutor threadPoolExecutor(ThreadPoolConfigProperties pool) {
return new ThreadPoolExecutor(pool.getCoreSize(),
pool.getMaxSize(),
pool.getKeepAliveTime(),
TimeUnit.SECONDS,
new LinkedBlockingDeque<>(100000),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy());
}
}
When you use it, you just need to go through :
@Autowired
ThreadPoolExecutor executor;
2.2、CompletableFuture Combined asynchronous choreography
Future Interface
Future Interface (FutureTask Implementation class ) Defined operations Asynchronous task Implement some methods , For example, get the execution result of asynchronous task 、 Cancel the execution of the task 、 Judge whether the task is cancelled 、 Judge whether the task is completed, etc .
shortcoming :
get()
Blocking : Once the call get() Method to find the result , If the calculation is not completed, it will easily lead to program blocking .isDone()
polling : Rotation training will cost nothing CPU resources , And it is not possible to get the calculation results in time .
CompletableFuture Yes Future Improvement
get() Method in Future It will be in... Until the calculation is completed Blocked state Next ,isDone() The method is easy to consume CPU resources , For real asynchronous processing, we hope to pass in callback functions , stay Future The callback function is called automatically at the end , such , We don't have to wait for the result .
The blocking method is contrary to the design concept of asynchronous choreography , And the way of rotation training will cost nothing CPU resources . therefore ,JDK8 Designed CompleatbleFuture.
CompleatbleFuture Provides a mechanism similar to the observer pattern , You can let the listener be notified when the task is completed .
public class CompletableFuture<T> implements Future<T>, CompletionStage<T>
Business scenario :
The logic of querying the product details page is complex , Some data needs to be called remotely , It must take more time to call :
- obtain sku Basic information of 0.5s
- obtain sku Picture information of 0.5s
- obtain sku Promotional information for 1s
- obtain spu All sales attributes of 1s
- Obtain the specification parameter group and the specification parameters under the group 1.5s
- spu details 1s
If each query on the product details page , It takes the time indicated below to complete . that , User needs 5.5s You can only see the contents of the product details page . Obviously unacceptable . If there are multiple threads doing this at the same time 6 Step by step , Maybe just 1.5s To complete the response
2.2.1、 Create asynchronous objects
Create asynchronous objects
CompletableFuture Four static methods are provided to create an asynchronous operation .
- runAsync Method does not support return value .
- supplyAsync Can support return value .
public static CompletableFuture<Void> runAsync(Runnable runnable)
public static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor)
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier)
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor)
Is not specified Executor The method will use ForkJoinPool.commonPool() Execute asynchronous code as its thread pool . If you specify a thread pool , Use the specified thread pool to run . All of the following methods are similar to .
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println("main...start....");
/** * Perception after method completion */
CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> {
System.out.println(" Current thread : " + Thread.currentThread().getId());
int i = 10 / 0;
System.out.println(" Running results :" + i);
return i;
}, executor).whenComplete((result,exception)->{
// Although you can get abnormal information , But you can't modify the returned data
System.out.println(" The asynchronous task completed successfully ... The result is :" + result+"; Exception is :"+exception);
}).exceptionally(throwable -> {
// You can sense the exception and return the specified default value
System.out.println(throwable);
return 10;
});
System.out.println(future2.get());
System.out.println("main...end....");
}
2.2.2、 Call back the method when the calculation is complete
Call back the method when the calculation is complete
When CompletableFuture The result of calculation is finished , Or throw an exception , Can perform specific Action. Mainly the following methods :
// Can handle exceptions , No return value
public CompletableFuture<T> whenComplete(BiConsumer<? super T,? super Throwable> action)
public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T,? super Throwable> action)
public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T,? super Throwable> action, Executor executor)
// Can handle exceptions , There is a return value
public CompletableFuture<T> exceptionally(Function<Throwable,? extends T> fn)
whenComplete It can handle normal and abnormal calculation results 【 perception 】,exceptionally Handling exceptions 【 modify 】
whenComplete and whenCompleteAsync The difference between :
- whenComplete : The thread executing the current task continues to execute whenComplete The task of
- whenCompleteAsync : It's Executive whenCompleteAsync This task continues to be submitted to the thread pool for execution
The method is different Async ending , signify Action Execute with the same thread , and Async Other threads may be used to execute ( If the same thread pool is used , It may also be executed by the same thread )
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println("main...start....");
/* CompletableFuture<Void> future1 = CompletableFuture.runAsync(() -> { System.out.println(" Current thread : " + Thread.currentThread().getId()); int i = 10 / 2; System.out.println(" Running results :" + i); }, executor);*/
CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> {
System.out.println(" Current thread : " + Thread.currentThread().getId());
int i = 10 / 0;
System.out.println(" Running results :" + i);
return i;
}, executor).whenComplete((result,exception)->{
// Although you can get abnormal information , But you can't modify the returned data
System.out.println(" The asynchronous task completed successfully ... The result is :" + result+"; Exception is :"+exception);
}).exceptionally(throwable -> {
// You can sense the exception and return the specified default value
return 10;
});
System.out.println(future2.get());
System.out.println("main...end....");
}
2.2.3、handle Method
handle Method
handle It is the processing of the result when the task is completed . handle Methods and thenApply The method is basically the same . The difference is :
- handle It's done after the task , You can also handle abnormal tasks .
- thenApply Only normal tasks can be performed , If the task is abnormal, it will not be executed thenApply Method .
public <U> CompletionStage<U> handle(BiFunction<? super T, Throwable, ? extends U> fn);
public <U> CompletionStage<U> handleAsync(BiFunction<? super T, Throwable, ? extends U> fn);
public <U> CompletionStage<U> handleAsync(BiFunction<? super T, Throwable, ? extends U> fn,Execut
/** * Processing after method execution */
CompletableFuture<Integer> future3 = CompletableFuture.supplyAsync(() -> {
System.out.println(" Current thread : " + Thread.currentThread().getId());
int i = 10 / 2;
System.out.println(" Running results :" + i);
return i;
}, executor).handle((res,thr)->{
if (res != null) {
return res *2;
}
if (thr != null) {
return 0;
}
return 0;
});
System.out.println(future3.get());
2.2.4、 Thread serialization
Thread serialization
- thenRun Method :
As long as the above tasks are completed , We'll start thenRun, As long as you finish the task , perform thenRun Subsequent actions for - thenAccept Method :
Consumption processing results . Receive the processing result of the task , And consumption processing , No results returned . - thenApply Method :
When one thread depends on another , Get the result returned by the previous task , And return the return value of the current task .
with Async By default, it is executed asynchronously . Same as before
- No Asycn : Share the same thread
- belt Asycn : Give it to the thread pool for execution
// thenRun
public CompletableFuture<Void> thenRun(Runnable action);
public CompletionStage<Void> thenRunAsync(Runnable action);
public CompletionStage<Void> thenRunAsync(Runnable action,
Executor executor);
// thenAccept
public CompletableFuture<Void> thenAccept(Consumer<? super T> action);
public CompletionStage<Void> thenAcceptAsync(Consumer<? super T> action);
public CompletionStage<Void> thenAcceptAsync(Consumer<? super T> action,
Executor executor);
public <U> CompletableFuture<U> thenApply(Function<? super T,? extends U> fn);
public <U> CompletionStage<U> thenApplyAsync
(Function<? super T,? extends U> fn);
public <U> CompletionStage<U> thenApplyAsync
(Function<? super T,? extends U> fn,
Executor executor);
Test code :
/** * Thread serialization * 1)、thrnRun : Cannot get the execution result of the previous step , No return value * 2)、thenAccept : Can receive the result of the previous step , But no return value * 3)、thenApply : Can receive the result of the previous step , And it has a return value */
CompletableFuture<Void> future1 = CompletableFuture.supplyAsync(() -> {
System.out.println(" Current thread 1: " + Thread.currentThread().getId());
int i = 10 / 2;
System.out.println(" Running results :" + i);
return i;
}, executor).thenRunAsync(() -> {
System.out.println(" Mission 2 Launched the ...");
}, executor);
CompletableFuture<Void> future2 = CompletableFuture.supplyAsync(() -> {
System.out.println(" Current thread 2: " + Thread.currentThread().getId());
int i = 10 / 2;
System.out.println(" Running results :" + i);
return i;
}, executor).thenAcceptAsync(res->{
System.out.println(" Mission 2 Launched the ..." + res);
},executor);
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
System.out.println(" Current thread 2: " + Thread.currentThread().getId());
int i = 10 / 2;
System.out.println(" Running results :" + i);
return i;
}, executor).thenApplyAsync(res -> {
System.out.println(" Mission 2 Launched the ..." + res);
return "Hello" + res;
}, executor);
System.out.println(" Return value :"+future.get());
2.2.5、 Two task combination - It's all done
Two task combination - It's all done
thenCombine Will put two CompletionStage After all the tasks are completed , Give the result of two tasks to thenCombine To deal with it .
runAfterBoth
Combine two future, There is no need to get future Result , Just two future After finishing the task , Deal with the task .Two CompletionStage, Only when the calculation is completed can the next operation be performed (Runnable)
public CompletionStage<Void> runAfterBoth(CompletionStage<?> other,Runnable action); public CompletionStage<Void> runAfterBothAsync(CompletionStage<?> other,Runnable action); public CompletionStage<Void> runAfterBothAsync(CompletionStage<?> other,Runnable action,Executor
thenAcceptBoth
Combine two future, Get two future The return result of the task , And then deal with the task , no return value
When two CompletionStage After execution is complete , Give the result to thenAcceptBoth To consumepublic <U> CompletionStage<Void> thenAcceptBoth(CompletionStage<? extends U> other,BiConsumer<? super T, ? super U> action); public <U> CompletionStage<Void> thenAcceptBothAsync(CompletionStage<? extends U> other,BiConsumer<? super T, ? super U> action); public <U> CompletionStage<Void> thenAcceptBothAsync(CompletionStage<? extends U> other,BiConsumer<? super T, ? super U> action, Executor executor);
thenCombine
Combine two future, Get two future Return result of , And return the return value of the current task
thenCombine Will be able to Two CompletionStage After all the tasks are completed , Give the result of two tasks to thenCombine To deal with it .public <U,V> CompletionStage<V> thenCombine(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn); public <U,V> CompletionStage<V> thenCombineAsync(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn); public <U,V> CompletionStage<V> thenCombineAsync(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn,Executor executor);
Test code :
/** * Both asynchronous tasks are completed */
CompletableFuture<Integer> future01 = CompletableFuture.supplyAsync(() -> {
System.out.println(" Mission 1 Threads : " + Thread.currentThread().getId());
int i = 10 / 4;
System.out.println(" Mission 1 end ");
return i;
}, executor);
CompletableFuture<String> future02 = CompletableFuture.supplyAsync(() -> {
System.out.println(" Mission 2 Threads : " + Thread.currentThread().getId());
System.out.println(" Mission 2 end ");
return "Hello";
}, executor);
future01.runAfterBothAsync(future02, ()->{
System.out.println(" Mission 3 Start ...");
},executor);
future01.thenAcceptBothAsync(future02, (f1,f2)->{
System.out.println(" Mission 3 Start , Previous results :f1="+f1+";f2="+f2);
},executor);
CompletableFuture<String> future = future01.thenCombineAsync(future02, (f1, f2) -> {
return f1 + ":" +f2 +"->HaHa";
}, executor);
System.out.println(" Method 3 Return result of :" + future.get());
2.2.6、 Two task combination - As long as one task is completed, execute the third
Two task combination - As long as one task is completed, execute the third
Two CompletionStage The return types should be consistent
runAfterEither Method
One of the two tasks is completed , There is no need to get future Result , Processing tasks , There is no return value
Two CompletionStage, Any one of them will perform the next operation (Runnable)public CompletionStage<Void> runAfterEither(CompletionStage<?> other,Runnable action); public CompletionStage<Void> runAfterEitherAsync(CompletionStage<?> other,Runnable action); public CompletionStage<Void> runAfterEitherAsync(CompletionStage<?> other,Runnable action,Executor executor);
acceptEither Method
One of the two tasks is completed , Get its return value , Processing tasks , No new return value
Two CompletionStage, Who performs the returned results quickly , I'll use that CompletionStage The result of the next consumption operation .public CompletionStage<Void> acceptEither(CompletionStage<? extends T> other,Consumer<? super T> action); public CompletionStage<Void> acceptEitherAsync(CompletionStage<? extends T> other,Consumer<? super T> action); public CompletionStage<Void> acceptEitherAsync(CompletionStage<? extends T> other,Consumer<? supe
applyToEither Method
One of the two tasks is completed , Get its return value , Process the task and have a new return value
Two CompletionStage, Who performs the returned results quickly , I'll use that CompletionStage The result of the next step of transformation operation .public <U> CompletionStage<U> applyToEither(CompletionStage<? extends T> other,Function<? super T, U> fn); public <U> CompletionStage<U> applyToEitherAsync(CompletionStage<? extends T> other,Function<? super T, U> fn); public <U> CompletionStage<U> applyToEitherAsync(CompletionStage<? extends T> other,Function<? sup
Test code :
/** * As long as one of the two asynchronous tasks is completed , We will carry out the task 3 * runAfterEither: Not aware of the results , I have no return value * acceptEither : Perception results , No return value */
CompletableFuture<Object> future01 = CompletableFuture.supplyAsync(() -> {
System.out.println(" Mission 1 Threads : " + Thread.currentThread().getId());
int i = 10 / 4;
System.out.println(" Mission 1 end ");
return i;
}, executor);
CompletableFuture<Object> future02 = CompletableFuture.supplyAsync(() -> {
System.out.println(" Mission 2 Threads : " + Thread.currentThread().getId());
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(" Mission 2 end ");
return "Hello";
}, executor);
// CompletableFuture<Void> future3 = future01.runAfterEitherAsync(future02, () -> {
// System.out.println(" Mission 3 Start ...");
// }, executor);
// CompletableFuture<Void> future4 = future01.acceptEitherAsync(future02, (res) -> {
// System.out.println(" Mission 3 Start ..." + res);
// }, executor);
CompletableFuture<String> future = future01.applyToEitherAsync(future02, res -> {
System.out.println(" Mission 3 Start ..." + res);
return res.toString() + "-->haha";
}, executor);
System.out.println("main...end...." + future.get());
}
2.2.7、 Multitasking
- allOf : Wait for all tasks to complete
- anyOf : Only one task is completed
public static CompletableFuture<Void> allOf(CompletableFuture<?>... cfs);
public static CompletableFuture<Object> anyOf(CompletableFuture<?>... cfs);
allOf Test code :
CompletableFuture<String> futureImg = CompletableFuture.supplyAsync(() -> {
System.out.println(" Query product picture information ");
return "hllo.jpg";
}, executor);
CompletableFuture<String> futureAttr = CompletableFuture.supplyAsync(() -> {
System.out.println(" Query the properties of goods ");
return " Starry sky white +256G";
}, executor);
CompletableFuture<String> futureDesc = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(" Inquire about the introduction of products ");
return " Apple ";
}, executor);
CompletableFuture<Void> allOf = CompletableFuture.allOf(futureImg, futureAttr, futureDesc);
allOf.get(); // Wait for all results to complete
System.out.println("main...end...." );
anyOf Test code :
CompletableFuture<String> futureImg = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(" Query product picture information ");
return "hllo.jpg";
}, executor);
CompletableFuture<String> futureAttr = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(" Query the properties of goods ");
return " Starry sky white +256G";
}, executor);
CompletableFuture<String> futureDesc = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(" Inquire about the introduction of products ");
return " Apple ";
}, executor);
CompletableFuture<Object> anyOf = CompletableFuture.anyOf(futureImg, futureAttr, futureDesc);
anyOf.get();
边栏推荐
- 浅谈日志中的返回格式封装格式处理,异常处理
- leetcode-560:和为 K 的子数组
- JMeter about setting thread group and time
- . Net configuration system
- The width of table is 4PX larger than that of tbody
- AHB bus in stm32_ Apb2 bus_ Apb1 bus what are these
- table宽度比tbody宽度大4px
- 【华为机试真题详解】高矮个子排队
- IDA中常见快捷键
- [daiy5] jz77 print binary tree in zigzag order
猜你喜欢
How to cancel automatic saving of changes in sqlyog database
P1031 [NOIP2002 提高组] 均分纸牌
Yarn的基础介绍以及job的提交流程
对word2vec的一些浅层理解
P2788 数学1(math1)- 加减算式
对存储过程进行加密和解密(SQL 2008/SQL 2012)
Five simple and practical daily development functions of chrome are explained in detail. Unlock quickly to improve your efficiency!
Encrypt and decrypt stored procedures (SQL 2008/sql 2012)
Some properties of leetcode139 Yang Hui triangle
【acwing】789. 数的范围(二分基础)
随机推荐
Appx代碼簽名指南
XML configuration file parsing and modeling
HDU-2196 树形DP学习笔记
Guide de signature du Code Appx
Study summary of postgraduate entrance examination in September
深入分析ERC-4907协议的主要内容,思考此协议对NFT市场流动性意义!
基于gis三维可视化技术的智慧城市建设
About hzero resource error (groovy.lang.missingpropertyexception: no such property: weight for class)
C logging method
Kotlin realizes wechat interface switching (fragment exercise)
Why is the reflection efficiency low?
对存储过程进行加密和解密(SQL 2008/SQL 2012)
AHB bus in stm32_ Apb2 bus_ Apb1 bus what are these
ArrayList线程不安全和解决方案
The story of Plato and his three disciples: how to find happiness? How to find the ideal partner?
根据设备信息进行页面跳转至移动端页面或者PC端页面
JMeter installation
【acwing】789. 数的范围(二分基础)
[email protected]能帮助我们快速拿到日志对象
String formatting