멀티스레드 비동기 오케스트레이션 예시에 대한 자세한 설명

1. 멀티스레딩 검토

목차

1. 멀티스레딩 검토

1. 스레드를 초기화하는 4가지 방법

2. 스레드 풀의 7개 매개변수

3. 네 가지 일반적인 스레드 풀 유형

4. 개발 시 스레드 풀을 사용하는 이유는 무엇입니까?

2. CompletableFuture 비동기 오케스트레이션

1. 비동기 객체 생성

2. 계산 완료 시 콜백 방법 

3. 핸들 방식

4. 스레드 직렬화 방법

5. 두 가지 작업 조합 - 둘 다 완료해야 합니다.

6. 두 가지 작업 조합 - 하나가 완료됨

7. 멀티 태스킹 조합


 

1. 스레드를 초기화하는 4가지 방법

1) 스레드 상속

Thread thread = new Thread01();
thread.start();

2) Runnable 인터페이스 구현

Runnable01 runnable01 = new Runnable01();
new Thread(runnable01).start();

3) Callable 인터페이스 + FutureTask 구현(반환 결과를 얻고 예외를 처리할 수 있음)

FutureTask futureTask = new FutureTask<>(new Callable01());
new Thread(futureTask).start();
// 阻塞等待线程执行完成,获取返回结果
Integer i = (Integer) futureTask.get();

4) 스레드 풀

public static ExecutorService service = Executors.newFixedThreadPool(10);
service.execute(new Runnable01());

        다음 두 가지 방법으로 스레드 풀을 초기화합니다.

Executors.newFiexedThreadPool(3);
//或者
new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit unit, workQueue, threadFactory, 
차이점:
 Thread와 Runnable은 반환 값을 얻을 수 없고 Callable은 반환 값을 얻을 수 있습니다. 
Thread, Runnable, Callable은 리소스를 제어할 수 없지만 스레드 풀은 리소스를 제어할 수 있습니다. 스레드 풀을 
통해 성능이 안정적이며 실행 결과를 얻을 수 있습니다. 도 얻을 수 있고 예외도 포착할 수 있습니다. 그러나 복잡한 비즈니스 상황에서는 하나의 비동기 호출이 다른 비동기 호출의 실행 결과에 따라 달라질 수 있습니다.

2. 스레드 풀의 7개 매개변수

/**
     * Creates a new {@code ThreadPoolExecutor} with the given initial
     * parameters.
     *
     * @param corePoolSize the number of threads to keep in the pool, even
     *        if they are idle, unless {@code allowCoreThreadTimeOut} is set
     * @param maximumPoolSize the maximum number of threads to allow in the
     *        pool
     * @param keepAliveTime when the number of threads is greater than
     *        the core, this is the maximum time that excess idle threads
     *        will wait for new tasks before terminating.
     * @param unit the time unit for the {@code keepAliveTime} argument
     * @param workQueue the queue to use for holding tasks before they are
     *        executed.  This queue will hold only the {@code Runnable}
     *        tasks submitted by the {@code execute} method.
     * @param threadFactory the factory to use when the executor
     *        creates a new thread
     * @param handler the handler to use when execution is blocked
     *        because the thread bounds and queue capacities are reached
     * @throws IllegalArgumentException if one of the following holds:<br>
     *         {@code corePoolSize < 0}<br>
     *         {@code keepAliveTime < 0}<br>
     *         {@code maximumPoolSize <= 0}<br>
     *         {@code maximumPoolSize < corePoolSize}
     * @throws NullPointerException if {@code workQueue}
     *         or {@code threadFactory} or {@code handler} is null
     */
    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

7가지 핵심 매개변수: 

corePoolSize: 코어 스레드 수, 스레드 풀이 생성된 후 준비되어 비동기 작업 수신을 기다리는 스레드 수입니다.

maximumPoolSize: 최대 스레드 수, 제어 리소스

keepAliveTime: 생존 시간. 현재 스레드 수가 코어 스레드 수보다 크거나 스레드의 유휴 시간이 지정된 keepAliveTime보다 크면 스레드가 해제됩니다. (최대 스레드 수 - 코어 스레드 수)

단위: 시간 단위

BlockingQueue<Runnable> workQueue: 차단 대기열입니다. 작업이 너무 많으면 현재 작업 수만큼 대기열에 배치됩니다(Runable 실행을 사용하여 제출된 작업). 유휴 스레드가 있으면 작업이 대기열에서 제거되어 실행됩니다.

ThreadFactory: 스레드 생성을 위한 팩토리

RejectedExecutionHandler 핸들러: 큐가 가득 찬 경우 지정된 거부 정책에 따라 작업 실행을 거부합니다.

차단 큐의 제한되지 않은 큐와 제한된 큐:

Bounded queue : 고정된 크기의 큐입니다. 예를 들어 고정 크기의 LinkedBlockingQueue가 설정되거나 크기가 0인 동기 대기열이 생산자와 소비자 간의 전송에만 사용됩니다.

Unbounded queue : 고정된 크기를 갖지 않는 큐를 말한다. 이러한 대기열의 특징은 오버플로될 때까지 직접 대기열에 넣을 수 있다는 것입니다. 물론 현실에서는 이렇게 큰 용량(Integer.MAX_VALUE 초과)을 갖는 경우가 거의 없으므로 사용자 경험에서 볼 때 이는 "무제한"과 동일합니다. 예를 들어 고정된 크기의 LinkedBlockingQueue 세트가 없습니다.

*실행 프로세스:

1. 스레드 풀을 생성하고, 코어 스레드 수를 준비하고, 작업 수락을 준비합니다.

2. 새로운 작업이 들어오면 코어가 준비한 유휴 스레드를 사용하여 실행됩니다.

        (1) 코어가 가득 차면 들어오는 작업이 차단 대기열에 들어갑니다. 유휴 코어는 작업 실행을 얻기 위해 대기열을 차단합니다.

        (2) 블로킹 큐가 가득 차면 새 스레드가 직접 열려 실행되며, 최대 개수는 max에 지정된 개수까지만 열 수 있습니다.

        (3)과 max가 모두 실행됩니다. 유휴 스레드의 최대 코어 수는 keepAliveTime에 지정된 시간이 지나면 자동으로 삭제됩니다. 마지막으로 코어 크기로 유지됩니다.

        (4) 스레드 수가 최대 개수에 도달하여 새로운 작업이 들어오면, 거절로 지정된 거절 정책이 처리에 사용됩니다.

3. 모든 스레드는 지정된 팩토리에서 생성됩니다.

3. 네 가지 일반적인 스레드 풀 유형

newCachedThreadPool: 캐시 가능한 스레드 풀을 생성합니다. 스레드 풀의 길이가 처리 요구 사항을 초과하면 유휴 스레드를 유연하게 재활용할 수 있으며, 재활용할 방법이 없으면 새 스레드가 생성됩니다.

newFixedThreadPool: 최대 동시 스레드 수를 제어할 수 있는 고정 길이 스레드 풀을 생성합니다. 초과 스레드는 대기열에서 대기합니다.

newScheduledThreadPool: 예약 및 주기적인 작업 실행을 지원하기 위해 고정 길이 스레드 풀을 만듭니다.

newSingleThreadExecutor: 고유한 작업자 스레드만 사용하여 작업을 실행하는 단일 스레드 스레드 풀을 생성하여 모든 작업이 지정된 순서(FIFO, LIFO, 우선 순위)로 실행되도록 보장합니다.

4. 개발 시 스레드 풀을 사용하는 이유는 무엇입니까?

  • 자원 소모 감소: 이미 생성된 스레드를 재사용하여 스레드 생성 및 소멸로 인한 손실을 줄입니다.
  • 응답 속도 향상: 스레드 풀의 스레드 수가 스레드 풀의 최대 제한을 초과하지 않을 때 일부 스레드는 할당된 작업을 기다리는 상태이므로 작업이 오면 새 스레드를 생성하지 않고도 실행할 수 있습니다. .
  • 스레드 관리 효율성 향상: 스레드 풀은 현재 시스템 특성을 기반으로 풀의 스레드를 최적화하여 스레드 생성 및 삭제로 인한 시스템 오버헤드를 줄입니다. 스레드의 무제한 생성 및 소멸은 시스템 자원을 소모할 뿐만 아니라 시스템의 안정성을 저하시키므로 통합 할당을 위해 스레드 풀을 사용하십시오.

2. CompletableFuture 비동기 오케스트레이션

        비즈니스 시나리오: 제품 세부 정보 페이지를 쿼리하는 논리는 상대적으로 복잡하고 일부 데이터를 원격으로 호출해야 하므로 필연적으로 더 많은 시간이 소요됩니다.

5ca33d7bce6d4506a6050cc827358db7.png

       제품 세부 정보 페이지의 각 쿼리를 완료하는 데 아래 표시된 시간이 필요한 경우 사용자가 제품 세부 정보 페이지의 내용을 보는 데 5.5초가 소요됩니다. 분명히 이것은 받아 들일 수 없습니다. 여러 스레드가 이 6단계를 동시에 완료하는 경우 응답을 완료하는 데 1.5초밖에 걸리지 않습니다.


        Future는 비동기 계산 결과를 설명하기 위해 Java 5에 추가된 클래스입니다. `isDone` 메소드를 사용하여 계산이 완료되었는지 확인하거나 `get`을 사용하여 계산이 완료될 때까지 호출 스레드를 차단하고 결과를 반환할 수 있습니다. 또한 `cancel` 메소드를 사용하여 실행을 중지할 수도 있습니다. 작업.

         `Future` 및 관련 사용법은 작업을 비동기적으로 실행할 수 있는 기능을 제공하지만 결과를 얻는 것이 매우 불편하며 작업의 결과는 차단 또는 폴링을 통해서만 얻을 수 있습니다. 블로킹 방식은 분명히 우리 비동기 프로그래밍의 원래 의도에 어긋나며 폴링 방식은 불필요한 CPU 리소스를 소모하고 제때에 계산 결과를 얻을 수 없습니다. 왜 우리는 계산이 완료될 때 리스너에게 제때에 알리기 위해 관찰자 디자인 패턴을 사용할 수 없는 걸까요? 결과는 완성?모직물?

         Node.js와 같은 많은 언어는 콜백을 사용하여 비동기 프로그래밍을 구현합니다. Netty와 같은 일부 Java 프레임워크는 Java의 'Future' 인터페이스를 확장하고 'addListener'와 같은 여러 확장 메서드를 제공합니다. Google guava는 일반 확장 Future도 제공합니다. Scala는 사용하기 쉽고 강력한 Future/Promise 비동기 프로그래밍도 제공합니다. 모델.

        정통 Java 클래스 라이브러리로서 자체 라이브러리의 기능을 향상시키기 위해 뭔가를 해야 할까요?

        Java 8에는 약 50개의 메소드를 포함하는 새로운 클래스가 추가되었습니다: 매우 강력한 Future 확장 기능을 제공하는 CompletableFuture는 비동기 프로그래밍의 복잡성을 단순화하는 데 도움이 되며 콜백을 통해 함수형 프로그래밍 기능을 제공합니다. 방식과 CompletableFuture를 변환하고 결합하는 방법을 제공합니다. CompletableFuture 클래스는 Future 인터페이스를 구현하므로 이전과 마찬가지로 `get` 메서드를 사용하여 차단하거나 폴링하여 결과를 얻을 수 있지만 이 방법은 권장되지 않습니다.

        CompletableFuture와 FutureTask는 모두 Future 인터페이스의 구현 클래스에 속하며 둘 다 스레드의 실행 결과를 얻을 수 있습니다.

5329b3b6a74849139d7d57b8824a7687.png

1. 비동기 객체 생성

CompletableFuture는 비동기 작업을 생성하기 위한 네 가지 정적 메서드를 제공합니다.

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)

1. runXxxx는 결과를 반환하지 않지만, SupplyXxx는 반환 결과를 얻을 수 있습니다.

2. 사용자 정의 스레드 풀을 전달할 수 있습니다. 그렇지 않으면 기본 스레드 풀이 사용됩니다.

2. 계산 완료 시 콜백 방법 

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)
public CompletableFuture<T> exceptionally(Function<Throwable, ? extends T> fn)

whenComplete는 정상 및 비정상 계산 결과를 처리할 수 있으며(성공 콜백), 비정상 상황을 예외적으로 처리(예외 콜백)할 수 있습니다.

whenComplete와 whenCompleteAsync의 차이점은 다음과 같습니다.

         whenComplete: 현재 작업을 실행하는 스레드가 whenComplete 작업을 계속 실행합니다. 

        whenCompleteAsync: 실행이 실행을 위해 스레드 풀에 whenCompleteAsync 작업을 계속 제출합니다.

메서드가 Async로 끝나지 않습니다. 즉, Action은 동일한 스레드를 사용하여 실행되고 Async는 다른 스레드를 사용하여 실행될 수 있습니다. (동일한 스레드 풀을 사용하는 경우 동일한 스레드에서 실행을 위해 선택할 수도 있습니다.)

public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.out.println("Main...Start...."+Thread.currentThread());
        // supplyAsync 可获取返回值
        CompletableFuture<Integer> result = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程" + Thread.currentThread());
            int i = 10 / 0;
            System.out.println("运行结果:" + i);
            return i;
        }, threadPool).whenCompleteAsync((res,exception)->{
            // 当上面的任务执行完成,能得到结果和异常信息,但无法修改返回值
            System.out.println("异步任务完成,结果为:"+res+",异常为:"+exception);
        }).exceptionally(throwable -> {
            // 可以感知异常,同时返回默认值
            return 101;
        });
        Integer integer = result.get();
        System.out.println("Main...End...."+integer);

    }

결과:

Main...Start....Thread[main,5,main]
当前线程Thread[pool-1-thread-1,5,main]
异步任务完成,结果为:null,异常为:java.util.concurrent.CompletionException: java.lang.ArithmeticException: / by zero
Main...End....101

then과 유사하며 ES6의 Promise를 거부합니다.

3. 핸들 방식

public static void main(String[] args) throws ExecutionException, InterruptedException {
        /**
         * 方法执行完成后的处理
         */
        System.out.println("Main...Start...."+Thread.currentThread());
        CompletableFuture<Integer> result = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程" + Thread.currentThread());
            int i = 10 / 2;
            System.out.println("运行结果:" + i);
            return i;
        }, threadPool).handle((res,throwable)->{
            // handle可获取到返回值并可进行修改,且可以感知异常,并修改返回值
            if(res!=null && throwable==null){
                return res;
            }else{
                return 0;
            }
        });
        Integer integer = result.get();
        System.out.println("Main...End...."+integer);

    }

결과:

Main...Start....Thread[main,5,main]
当前线程Thread[pool-1-thread-1,5,main]
Main...End....0

4. 스레드 직렬화 방법

public <U> CompletableFuture<U> thenApply(Function<? super T,? extends U> fn)
public <U> CompletableFuture<U> thenApplyAsync(Function<? super T,? extends U> fn)
public <U> CompletableFuture<U> thenApplyAsync(Function<? super T,? extends U> fn, Executor executor)

public CompletableFuture<Void> thenAccept(Consumer<? super T> action)
public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action)
public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action,Executor executor)


public CompletableFuture<Void> thenRun(Runnable action)
public CompletableFuture<Void> thenRunAsync(Runnable action)
public CompletableFuture<Void> thenRunAsync(Runnable action,Executor executor)

thenApply 메소드: 스레드가 다른 스레드에 의존하는 경우 이전 작업에서 반환된 결과를 얻고 현재 작업의 반환 값을 반환합니다.

thenAccept 메소드: 처리 결과를 소비합니다. 작업의 처리 결과를 수신하고 결과를 반환하지 않고 처리를 소비합니다.

thenRun 방법: 위 작업이 완료되면 thenRun이 실행됩니다. 작업이 처리된 후에만 thenRun의 후속 작업이 실행됩니다.

Async를 사용하면 기본적으로 실행이 비동기식입니다. 이전과 같습니다.

위의 전제조건 작업이 성공적으로 완료되어야 합니다.

기능<? 슈퍼 T,? U>를 연장한다

        T: 이전 작업에서 반환된 결과 유형

        U: 현재 작업의 반환 값 유형

public static void main(String[] args) throws ExecutionException, InterruptedException {
        /**
         * 线程串行化
         *  1、thenRunAsync:无法获取上一步的执行结果,无返回值
         *  .thenRunAsync(() -> {
         *             System.out.println("任务2启动了");
         *         },threadPool)
         *  2、thenAcceptAsync:能获取到上一步的返回值,无返回值
         *  .thenAcceptAsync(res -> {
         *             System.out.println("任务2启动了"+res);
         *         },threadPool)
         *  3、thenApplyAsync:既能获取到上一步的返回值,有返回值
         */
        System.out.println("Main...Start...."+Thread.currentThread());
        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程" + Thread.currentThread());
            int i = 10 / 2;
            System.out.println("运行结果:" + i);
            return i;
        }, threadPool).thenApplyAsync(res->{
            System.out.println("任务2启动了"+res);
            return "hello,"+res;
        },threadPool);
        //future.get() 获取返回值,会阻塞
        System.out.println("Main...End...."+future.get());

    }

결과:

Main...Start....Thread[main,5,main]
当前线程Thread[pool-1-thread-1,5,main]
运行结果:5
任务2启动了5
Main...End....hello,5

5. 두 가지 작업 조합 - 둘 다 완료해야 합니다.

public <U,V> CompletableFuture<V> thenCombine(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn)
public <U,V> CompletableFuture<V> thenCombineAsync(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn)
public <U,V> CompletableFuture<V> thenCombineAsync(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn, Executor executor)
public <U> CompletableFuture<Void> thenAcceptBoth(CompletionStage<? extends U> other,BiConsumer<? super T, ? super U> action)
public <U> CompletableFuture<Void> thenAcceptBoth(CompletionStage<? extends U> other,BiConsumer<? super T, ? super U> action)
public <U> CompletableFuture<Void> thenAcceptBothAsync(CompletionStage<? extends U> other,BiConsumer<? super T, ? super U> action, Executor executor)
public CompletableFuture<Void> runAfterBoth(CompletionStage<?> other,Runnable action)
public CompletableFuture<Void> runAfterBothAsync(CompletionStage<?> other,Runnable action)
public CompletableFuture<Void> runAfterBothAsync(CompletionStage<?> other,Runnable action,Executor executor)

이 작업을 트리거하려면 두 작업을 모두 완료해야 합니다.

thenCombine: 두 future를 결합하고, 두 future의 반환 결과를 얻고, 현재 작업의 반환 값을 반환합니다.

 thenAcceptBoth: 두 future를 결합하고 두 future 작업의 반환 결과를 얻은 다음 값을 반환하지 않고 작업을 처리합니다.

runAfterBoth: 두 개의 future를 결합합니다. future의 결과를 얻을 필요가 없으며 두 개의 future가 작업을 처리한 후에만 작업을 처리하면 됩니다.

:

먼저 두 개의 작업을 만듭니다.

/**
 * 两个都完成
 */
System.out.println("Main...Start...."+Thread.currentThread());
CompletableFuture<Integer> future01 = CompletableFuture.supplyAsync(() -> {
    System.out.println("任务1开始" + Thread.currentThread().getId());
    int i = 10 / 2 ;
    System.out.println("任务1结束");
    return i;
}, threadPool);

CompletableFuture<String> future02 = CompletableFuture.supplyAsync(() -> {
    System.out.println("任务2开始"+Thread.currentThread().getId());
    System.out.println("任务2结束");
    return "Hello";
}, threadPool);

runAfterBothAsync를 사용하십시오(이전 작업 실행 결과를 얻을 수 없음).

future01.runAfterBothAsync(future02,()->{
    System.out.println("任务3启动");
},threadPool);

// 结果:

Main...Start....Thread[main,5,main]
任务1开始12
任务1结束
任务2开始13
任务2结束
任务3启动

thenAcceptBothAsync를 사용하세요(이전 작업 실행 결과를 얻을 수 있지만 반환할 수는 없음).

future01.thenAcceptBothAsync(future02,(f1,f2)->{
    System.out.println("任务3开始----f1结果:"+f1+"===f2结果"+f2);
},threadPool);

// 结果:

Main...Start....Thread[main,5,main]
任务1开始12
任务1结束
任务2开始13
任务2结束
任务3开始----f1结果:5===f2结果Hello

thenCombineAsync를 사용하십시오(이전 작업 실행 결과를 얻고 결과를 수정하고 반환할 수 있음).

CompletableFuture<String> future = future01.thenCombineAsync(future02, (f1, f2) -> {
    return f1 +":"+ f2 + "--->Hello";
}, threadPool);
System.out.println("Main...End...."+future.get());

// 结果:
Main...Start....Thread[main,5,main]
任务1开始12
任务1结束
任务2开始13
任务2结束
Main...End....5:Hello--->Hello

6. 두 가지 작업 조합 - 하나가 완료됨

public CompletableFuture<Void> runAfterEither(CompletionStage<?> other,Runnable action)
public CompletableFuture<Void> runAfterEitherAsync(CompletionStage<?> other,Runnable action)
public CompletableFuture<Void> runAfterEitherAsync(CompletionStage<?> other,Runnable action,Executor executor)
public CompletableFuture<Void> acceptEither(CompletionStage<? extends T> other, Consumer<? super T> action)
public CompletableFuture<Void> acceptEitherAsync(CompletionStage<? extends T> other, Consumer<? super T> action)
public CompletableFuture<Void> acceptEitherAsync(CompletionStage<? extends T> other, Consumer<? super T> action,Executor executor)
public <U> CompletableFuture<U> applyToEither(CompletionStage<? extends T> other, Function<? super T, U> fn)
public <U> CompletableFuture<U> applyToEitherAsync(CompletionStage<? extends T> other, Function<? super T, U> fn)
public <U> CompletableFuture<U> applyToEitherAsync(CompletionStage<? extends T> other, Function<? super T, U> fn,Executor executor)

두 작업 중 향후 작업이 완료되면 해당 작업이 실행됩니다.

applyToEither: 두 작업 중 하나가 완료되어 반환 값을 얻고 작업을 처리하고 새 반환 값을 갖습니다. acceptEither: 두 작업 중 하나가 완료되어 반환 값을 얻은 후 작업을 처리합니다. 새로운 반환 값은 없습니다. runAfterEither: 두 작업 중 하나가 완료되었습니다. 미래의 결과를 얻고 작업을 처리할 필요가 없으며 반환 값이 없습니다.

7. 멀티 태스킹 조합

public static CompletableFuture<Void> allOf(CompletableFuture<?>... cfs)
public static CompletableFuture<Object> anyOf(CompletableFuture<?>... cfs)

allOf: 모든 작업이 완료될 때까지 기다립니다.

anyOf: 하나의 작업이 완료되는 한

예:

사용자가 홈페이지를 로드할 때 데이터 수집을 시뮬레이션하는 세 가지 작업을 만듭니다.

CompletableFuture<String> futureImg = CompletableFuture.supplyAsync(() -> {
    System.out.println("查询商品图片信息");
    return "hello.jpg";
}, threadPool);

CompletableFuture<String> futureAttr = CompletableFuture.supplyAsync(() -> {
    System.out.println("查询商品属性");
    return "白色+1TB";
}, threadPool);

CompletableFuture<String> futureDesc = CompletableFuture.supplyAsync(() -> {
    System.out.println("查询商品介绍");
    return "Apple";
}, threadPool);

모두 사용:

CompletableFuture<Void> allOf = CompletableFuture.allOf(futureImg, futureAttr, futureDesc);

allOf.get(); // 等待所有任务执行完成 返回结果

// 获取所有任务的执行结果
System.out.println("Main...End...."+futureImg.get()+"===>"+futureAttr.get()+"===>"+futureDesc.get());

// 结果:
Main...Start....Thread[main,5,main]
查询商品图片信息
查询商品属性
查询商品介绍
Main...End....hello.jpg===>白色+1TB===>Apple

다음 중 하나를 사용하십시오.

CompletableFuture<Object> anyOf = CompletableFuture.anyOf(futureImg, futureAttr, futureDesc);
anyOf.get(); // 有一个任务执行完成 返回结果

// 获取所有任务的执行结果
System.out.println("Main...End...."+anyOf.get());

// 结果:
Main...Start....Thread[main,5,main]
查询商品图片信息
查询商品属性
Main...End....hello.jpg
查询商品介绍

 

 

추천

출처blog.csdn.net/weixin_53922163/article/details/128177316