CompletableFuture으로, 비동기 프로그래밍을하는 것은 그렇게 어려운 일이 아니다!

이 문서 검토 :

  • 비즈니스 수요 시나리오에 대해 설명
  • 기술 디자인 사고
  • 미래의 실제 디자인 패턴
  • CompletableFuture 전투 모드
  • CompletableFuture 생산 제안
  • CompletableFuture 성능 테스트
  • CompletableFuture 확장

1, 비즈니스 수요 시나리오에 대해 설명


같은 일이 항상 변화하고 있습니다.

아마도, 자신의 여가 시간에있는 모든 사람, 자주, 자주 Youku 등 여러 가지 APP로, 비디오를보고는, 텐센트를 환상적인 예술을 사랑 해요.

이 비디오는 휴대 전화에 전용 APP을 재생할 수 있습니다뿐만 아니라 TV에서 재생을 지원합니다.

APP 텔레비전 단말에서 재생 APP가 동일하지 않은 휴대 전화의 단부와, 독립 버전이다.

우리가 영화를 볼 때, 영화로 클릭, 플레이어가 자동으로 비디오를 재생됩니다, 페이지에이 시간을 앨범 세부 정보 페이지에 들어갔다. 사용자는 전화 앨범 세부 정보 페이지에보고, 텔레비전 스페셜 세부 정보 페이지에 표시되는 페이지의 디자인 스타일이 다릅니다.

의 시각적 효과를 살펴 보자.

전화 텐센트 비디오 앨범 세부 정보 페이지 :

휴대 전화 앨범 세부 정보 페이지를 종료

샷의 상단 절반, 다음은 당신을 위해 스타 배우, 주변의 추천, 의견과 다른 기능을하는 것이 좋습니다.

따라서, TV 쇼 앨범 세부 정보 페이지의 끝에서 같은 방법이 아니다. 제품 관리자는 가설 자세한 내용은 요구 사항을 페이지를 개정 할 필요가 제안했다.
아래 그림과 같은 스타일의 요구 사항 :

TV 종료 앨범 세부 정보 페이지

TV를 측 앨범 세부 정보 페이지에서 두 터미널의 스타일 비교, 섹션의 많은, 더 많은 콘텐츠를 표시하는 각 부분의 가로가 포함되어 있습니다.

제품 디자인에 대한 요구 사항입니다 권장 내용에서 일부 판 및 검색에서 일부 판, 일부 부문 CMS (콘텐츠 관리 시스템)의 소스. , 추천에서 파생 된 다양한 소스의 각 섹션의 내용에 대한 이해 검색 할 간단하고 다른 콘텐츠 요구 사항 인터페이스는 실시간 요청 근처에 있습니다.

2, 기술 디자인 사고


계정에이 제품의 언급 수요를 복용 사실 어렵지 않다 구현합니다.

주요 부분들은 거의 실시간 데이터를위한 동적 인터페이스를 통해 제공되는 정적 인터페이스를 통해 얻을 수있다 자주 변경 데이터에 대해, 정적 데이터 및 동적 데이터 부분으로 분할된다.

정적 인터페이스 디자인 :

앨범 자체는 일반적으로 아래의 속성 데이터 및 비디오 앨범이 자주 변경되지 않는 것입니다.
도입 수요 시나리오, 나는 영화 채널을 쐈다. 텔레비전 채널 경우, 에피소드의 목록 (예 : 에피소드 1, 에피소드 2 ... 같은 앨범에있는 모든 동영상을) 보여, 비디오는 일반적으로 덜 빈번한 업데이트, 그래서 것 앨범 세부 정보 페이지 에피소드 목록의 데이터 당신은 정적 인터페이스에서 얻을 수 있습니다.

정적 인터페이스 데이터 생성 과정 :

정적 인터페이스 디자인

다른 부분은 동적 인터페이스를 달성 이러한 추천 검색 데이터와 같은 데이터를 획득하기 위해 써드 파티 인터페이스를 호출 할 필요가있다.
동시에, 판 반복 할 수 플레이트간에 콘텐츠의 요구 사항.

동적 인터페이스 디자인 :

옵션 중 하나 :

각 섹션의 표시 순서에 따라 직렬 인 호는 외부 데이터를 획득하기위한 적절한 인터페이스를 호출한다.

옵션 2 :

동시 통화, 평행하는 복수의 플레이트 사이, 즉 호출 응답하여 인터페이스의 전체 효율을 향상시킬 수있다.

사실,이 두 프로그램의 장점과 단점 각각.

옵션 개의 직렬 호출, 장점은 클라이언트로 모든 데이터를 통합 할 차례 호출 인터페이스, 콘텐츠 데이터 중복 제거에서 직렬 방식에 따라, 간단한 개발 모델이다.

그러나, 인터페이스 응답 시간은 일반적으로 타사 인터페이스는 항상 신뢰할 수 없습니다, 타사 인터페이스 응답 시간에 따라 달라집니다, 인터페이스는 인터페이스의 전체 처리량에 영향을 너무 오래 유지 스레드에지도 전체 응답 시간을 제기 할 수도 있습니다.

옵션 두 병렬 호출은, 이론적으로, 가장 느린 인터페이스의 응답 시간에 따라 여러 타사 인터페이스를 호출하는 동시에 그 가정 전체 인터페이스 응답 시간을 향상시킬 수 있습니다.

계정에 JVM 프로세스에 대한 너무 많은 스레드를 만들 제한 될 수 없다 "수영장 기술"에 대한 필요성을 고려하여 병렬로 호출합니다. 동시에, 또한 중량을 할 수있는 제품 설계의 순서에 따라, 고려 플레이트와 플레이트 사이에 데이터의 내용을 고려.

이 수요 시나리오에 따르면, 우리는 더 적절한 달성하기 위해 두 번째 옵션을 선택합니다.

옵션 II는 우리가 추상적 단순화 된 모델을 다음과 같이 선택한다 :

간단한 모델

T1은 T2는 T3 콘텐츠 블록 복수의 스레드를 나타낸다. 결과는 T2 스레드가 결과가 반복 될 수없는 반환하고 스레드 T1에 의해 반환 된 내용의 결과가, T3 스레드 T2 스레드는 중복 T1 두 개의 결과를 반환하는 결과가 없습니다 반환, 첫 번째 스레드 T1을 반환했습니다.

병렬 전화 여러 타사 인터페이스, 인터페이스는 반환에게 결과를 얻을 필요가있을 때 우리는 기술적 인 구현을 고려, 최초의 생각이 미래입니다, 비동기 작업 결과를 얻을 수 있습니다.

또한, JDK8 비동기 GET 결과는 모듈 형 비동기 프로그래밍을 달성하기 위해 더 우아한 방법으로, 일부의 사용의 미래에 고통 점을 해결하기 위해 도구를 사용뿐만 아니라 함수형 프로그래밍에 맞게 쉽게 CompletableFuture 제공합니다.

3, 미래의 디자인 패턴의 전투


미래 인터페이스 디자인 :

수집 작업 결과는 작업을 취소 제공, 작업 상태 인터페이스를 결정합니다. 메소드 호출이 작업의 결과를 얻을 수, 작업이 상황에서 완료되지 않은, 그것은 통화 차단 될 것입니다.

미래의 인터페이스 방법을 제공한다 :
`` `
// 작업 결과를 얻기
V get 및 ()을 예외 : InterruptedException, ExecutionException을 던졌습니다 ;

// 타임 아웃 지원 작업 결과를 얻기
V의 GET을 (롱 타임 아웃, TimeUnit와 단위)
예외 : InterruptedException, ExecutionException, TimeoutException가 발생합니다;

// 작업이 완료되었는지 여부를 확인
) (부울의 isDone을;

// 작업이 취소되었는지 여부를 확인
) (부울의 isCancelled을;

// 작업 취소
(가) (부울 mayInterruptIfRunning)을 취소 부울;
```

FutureTask ThreadPoolExecutor입니다 기능적 요구 사항을 구현하는 데 사용됩니다 미래는 작업 결과를 얻을 사용하는 경우 일반적으로, 우리는 고려.

ThreadPoolExecutor입니다, FutureTask도 관계 클래스와 미래 인터페이스 :

미래 디자인 클래스 다이어그램

제출 TheadPoolExecutor 세 가지 방법을 제공합니다 :

// 1. 提交无需返回值的任务,Runnable 接口 run() 方法无返回值
public Future<?> submit(Runnable task) {
}

// 2. 提交需要返回值的任务,Callable 接口 call() 方法有返回值
public <T> Future<T> submit(Callable<T> task) {
}

// 3. 提交需要返回值的任务,任务结果是第二个参数 result 对象
public <T> Future<T> submit(Runnable task, T result) {
}

다음 제출 번째 예시적인 방법은 :

static String x = "东升的思考";
public static void main(String[] args) throws Exception {
    ExecutorService executor = Executors.newFixedThreadPool(1);
    // 创建 Result 对象 r
    Result r = new Result();
    r.setName(x);

    // 提交任务
    Future<Result> future =
                    executor.submit(new Task(r), r);
    Result fr = future.get();

    // 下面等式成立
    System.out.println(fr == r);
    System.out.println(fr.getName() == x);
    System.out.println(fr.getNick() == x);
}

static class Result {
    private String name;
    private String nick;
    // ... ignore getter and setter 
}

static class Task implements Runnable {
    Result r;

    // 通过构造函数传入 result
    Task(Result r) {
            this.r = r;
    }

    @Override
    public void run() {
            // 可以操作 result
            String name = r.getName();
            r.setNick(name);
    }
}

결과는 사실이다.

FutureTask 설계 및 구현 :

의 Runnable와 미래 두 개의 인터페이스를 구현합니다. 의 Runnable 인터페이스, 그것은 수행 할 수있는 ThreadPoolExecutor에 직접 제출 한 작업 객체로 설명 할 수있다 구현합니다. 미래의 인터페이스 구현이 지침은 작업 결과를 반환 수행 할 얻을 수 있습니다.

제품에 따라 우리는 예에 의해 다음과 같은 기능을 달성하기 위해 두 개의 스레드 시뮬레이션 FutureTask를 사용합니다.
샘플 코드와 함께 이해 참고

public static void main(String[] args) throws Exception {
    // 创建任务 T1 的 FutureTask,调用推荐接口获取数据
    FutureTask<String> ft1 = new FutureTask<>(new T1Task());
    // 创建任务 T1 的 FutureTask,调用搜索接口获取数据,依赖 T1 结果
    FutureTask<String> ft2  = new FutureTask<>(new T2Task(ft1));
    // 线程 T1 执行任务 ft1
    Thread T1 = new Thread(ft1);
    T1.start();
    // 线程 T2 执行任务 ft2
    Thread T2 = new Thread(ft2);
    T2.start();
    // 等待线程 T2 执行结果
    System.out.println(ft2.get());
}

// T1Task 调用推荐接口获取数据
static class T1Task implements Callable<String> {
    @Override
    public String call() throws Exception {
            System.out.println("T1: 调用推荐接口获取数据...");
            TimeUnit.SECONDS.sleep(1);

            System.out.println("T1: 得到推荐接口数据...");
            TimeUnit.SECONDS.sleep(10);
            return " [T1 板块数据] ";
    }
}
        
// T2Task 调用搜索接口数据,同时需要推荐接口数据
static class T2Task implements Callable<String> {
    FutureTask<String> ft1;

    // T2 任务需要 T1 任务的 FutureTask 返回结果去重
    T2Task(FutureTask<String> ft1) {
         this.ft1 = ft1;
    }

    @Override
    public String call() throws Exception {
        System.out.println("T2: 调用搜索接口获取数据...");
        TimeUnit.SECONDS.sleep(1);

        System.out.println("T2: 得到搜索接口的数据...");
        TimeUnit.SECONDS.sleep(5);
        // 获取 T2 线程的数据
        System.out.println("T2: 调用 T1.get() 接口获取推荐数据");
        String tf1 = ft1.get();
        System.out.println("T2: 获取到推荐接口数据:" + tf1);

        System.out.println("T2: 将 T1 与 T2 板块数据做去重处理");
        return "[T1 和 T2 板块数据聚合结果]";
    }
}

다음과 같이 실행 결과는 다음과 같습니다

> Task :FutureTaskTest.main()
T1: 调用推荐接口获取数据...
T2: 调用搜索接口获取数据...
T1: 得到推荐接口数据...
T2: 得到搜索接口的数据...
T2: 调用 T1.get() 接口获取推荐数据
T2: 获取到推荐接口数据: [T1 板块数据] 
T2: 将 T1 与 T2 板块数据做去重处理
[T1 和 T2 板块数据聚合结果] 

요약 :

미래는 그것을 할 별도의 스레드로, 주로 어떤 작업의 시간이 소요되는 작업에의 "미래"라는 뜻을 나타낸다. 목적 비동기을 달성하기 위해, 결과를 반환하기 위해 기다릴 필요가없는 다른 작업을 계속 수행 할 수있는 현재의 thread 동안 작업의 결과를 제출 한 후, 현재 스레드의 작업을 제출하고 작업을 얻을.

4, CompleteableFuture 리얼 모드


미래 디자인 패턴을 위해, 우리가 작업을 제출하지만, 장애물을 입력하지 않지만, 호출자가이 작업 실행 결과를 얻을 때, 또는 작업이 완료 될 때까지 실행을 차단할 수 있습니다.

그들은 완벽한 향상을 얻기 전에이 문제는 디자인의 JDK1.5의 시작에 존재하고있다, 개발 JDK1.8은 CompletableFuture을 소개했다.

작업이 완료되면 한편, 구글의 오픈 소스 툴킷 구아바 ListenableFuture을 제공, 콜백을 지원하기 위해, 관심있는 친구들은 자신의 연구 지원에 액세스 할 수 있습니다.

비즈니스 수요 시나리오에 대한 소개에서, 데이터 소스의 다른 섹션은 다르며, 즉 판과 판 사이의 데이터 의존성이있다.

CompletableFuture를 제공하는 일부 기능에 따라, 작업과 작업 사이의 타이밍 관계로이 이해 될 수있다,이 비즈니스 시나리오에 적합합니다.

CompletableFuture 类 图 :

CompletableFuture 类 图

CompletableFuture는 미래와 CompletionStage 두 개의 인터페이스를 깨달았다. 미래의 인터페이스는 무엇을 말에 대해 우려 비동기 작업을 구현하고 비동기 작업 실행의 결과를 얻을 수 있습니다. 인터페이스를 구현 CompletionStage, 그 관계를 풀링 매우 풍부한 기능, 직렬 관계에 평행 관계를 제공한다.

CompletableFuture 코어의 장점 :

1) 수동 유지 보수 스레드없이 집중하는 개발자를 필요로하지 않고 작업에 할당 된 스레드;

2) 사용, 의미 더 명확;

예를 들어 : T3 = t1.thenCombine (T2, () -> {// 해봐요 ...} 명확하게 시작됩니다 작업 2의 완료를 기다리는 작업 3 일 후에 언급 될 수있다.

3)보다 간결 코드, 당신은 비즈니스 로직에 더 집중할 수 있도록 체인으로 연결된 통화를 지원합니다.

4) 취급이 용이 예외

다음으로, 앨범 다판 CompletableFuture 데이터 통합 ​​처리를 시뮬레이트한다.

코드는 다음과 같이 :

public static void main(String[] args) throws Exception {
    // 暂存数据
    List<String> stashList = Lists.newArrayList();
    // 任务 1:调用推荐接口获取数据
    CompletableFuture<String> t1 =
                    CompletableFuture.supplyAsync(() -> {
                            System.out.println("T1: 获取推荐接口数据...");
                            sleepSeconds(5);
                            stashList.add("[T1 板块数据]");
                            return "[T1 板块数据]";
                    });
    // 任务 2:调用搜索接口获取数据
    CompletableFuture<String> t2 =
                    CompletableFuture.supplyAsync(() -> {
                            System.out.println("T2: 调用搜索接口获取数据...");
                            sleepSeconds(3);
                            return " [T2 板块数据] ";
                    });
    // 任务 3:任务 1 和任务 2 完成后执行,聚合结果
    CompletableFuture<String> t3 =
                    t1.thenCombine(t2, (t1Result, t2Result) -> {
                            System.out.println(t1Result + " 与 " + t2Result + "实现去重逻辑处理");
                            return "[T1 和 T2 板块数据聚合结果]";
                    });
    // 等待任务 3 执行结果
    System.out.println(t3.get(6, TimeUnit.SECONDS));
}

static void sleepSeconds(int timeout) {
    try {
            TimeUnit.SECONDS.sleep(timeout);
    } catch (InterruptedException e) {
            e.printStackTrace();
    }
}

다음과 같이 실행 결과는 다음과 같습니다

> Task :CompletableFutureTest.main()
T1: 获取推荐接口数据...
T2: 调用搜索接口获取数据...
[T1 板块数据] 与  [T2 板块数据] 实现去重逻辑处理
[T1 和 T2 板块数据聚合结果]

새로운 클래스의 IDEA 위의 샘플 코드에서 제대로 실행하기 위해, 직접에 복사.

** 5, CompletableFuture 생산 제안 **


합리적인 스레드 풀을 만듭니다

프로덕션 환경에서 직접 추천 샘플 코드를 사용하지 않고. 에 사용 된 샘플 코드 때문에
CompletableFuture.supplyAsync(() -> {});
supplyAsync이 (팩토리 메소드 패턴으로 여기에 사용) () 메소드 CompletableFuture 오브젝트를 작성하는 데 기본적으로 사용되는 기본 스레드 풀, 비즈니스 요구를 충족 할 수 없습니다.

보기 기본 소스를 바인딩 :

// 默认使用 ForkJoinPool 线程池
private static final Executor asyncPool = useCommonPool ?
       ForkJoinPool.commonPool() : new ThreadPerTaskExecutor();

public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier) {
     return asyncSupplyStage(asyncPool, supplier);
}

ForkJoinPool 스레드 풀 만들기 :
기본 스레드 풀 크기가 Runtime.getRuntime ()이다 availableProcessors () - 1 (CPU의 코어 수는 --1), 당신은 -Djava.util.concurrent.ForkJoinPool.common.parallelism JVM 매개 변수에 의해 스레드 풀 크기를 설정할 수 있습니다.

JVM을 스레드 공장 매개 변수를 기반으로 -Djava.util.concurrent.ForkJoinPool.common.threadFactory 구성 설정, 설정이 두 매개 변수의 -Djava.util.concurrent.ForkJoinPool.common.exceptionHandler 구성 설정 예외 클래스, 내부 시스템을 통해 클래스 로더는 클래스를로드합니다.

모든 CompletableFuture 기본 스레드 풀을 사용하는 경우 작업 실행 속도가 느린 I / O 작업을하면, 그것은함으로써 전체 시스템 성능에 영향을 미치는 모든 스레드가 I / O 작업에 차단 이어질 것입니다.

따라서, 우리는 당신이 프로덕션 환경에서 사용하는 것이 좋습니다 根据不同的业务类型创建不同的线程池,以避免互相影响.

CompletableFuture 또한 스레드 풀을 지원하는 또 다른 방법을 제공합니다.

// 第二个参数支持传递 Executor 自定义线程池
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier,
                                                       Executor executor) {
        return asyncSupplyStage(screenExecutor(executor), supplier);
}

사용자 스레드 풀, 제안 된 참조 "수동 알리바바 자바 개발은"한정된 큐를 사용 ThreadPoolExecutor에 사용자 지정 스레드 풀을 권장, 큐의 크기는 실제 비즈니스 상황에 따라 설정된다.

은 "자바 동시성 진짜"책에 스레드 풀 크기 설정, 브라이언 게츠는 최적화 권장 사항을 많이 제공했다. 만약 컨텍스트 전환에 많은 시간의 결과로 스레드 풀, 경쟁력있는 CPU와 메모리 자원의 과도한 번호. 스레드 풀의 수, 너무 작은 경우, 당신은 멀티 코어 CPU의 장점을 최대한 활용 할 수 없습니다.

CPU 프로세서 스레드 풀 크기 이용률은 다음 식을 이용하여 추정 될 수있다 :

스레드 풀 크기를 계산

예외 처리 :

이러한 방법은 연쇄 프로그래밍을 지원하기로 CompletableFuture은 매우 간단한 예외 처리를 제공합니다.

// 类似于 try{}catch{} 中的 catch{}
public CompletionStage<T> exceptionally
        (Function<Throwable, ? extends T> fn);
                
// 类似于 try{}finally{} 中的 finally{},不支持返回结果
public CompletionStage<T> whenComplete
        (BiConsumer<? super T, ? super Throwable> action);
public CompletionStage<T> whenCompleteAsync
        (BiConsumer<? super T, ? super Throwable> action);
                
// 类似于 try{}finally{} 中的 finally{},支持返回结果
public <U> CompletionStage<U> handle
        (BiFunction<? super T, Throwable, ? extends U> fn);
public <U> CompletionStage<U> handleAsync
        (BiFunction<? super T, Throwable, ? extends U> fn);

#### 6, CompletableFuture 성능 테스트 :

태스크 도시 수의 압력을 측정 할 때마다 같은주기를 측정하는 압력 수렴의 중첩의 결과는 시간이 걸리는 계산 데이터 jobNum한다.
통계 크기 : CompletableFuture 기본 및 사용자 정의 스레드 풀 스레드 풀.
성능 시험 코드 :

// 性能测试代码
Arrays.asList(-3, -1, 0, 1, 2, 4, 5, 10, 16, 17, 30, 50, 100, 150, 200, 300).forEach(offset -> {
                    int jobNum = PROCESSORS + offset;
                    System.out.println(
                                    String.format("When %s tasks => stream: %s, parallelStream: %s, future default: %s, future custom: %s",
                                                    testCompletableFutureDefaultExecutor(jobNum), testCompletableFutureCustomExecutor(jobNum)));
});

// CompletableFuture 使用默认 ForkJoinPool 线程池
private static long testCompletableFutureDefaultExecutor(int jobCount) {
    List<CompletableFuture<Integer>> tasks = new ArrayList<>();
    IntStream.rangeClosed(1, jobCount).forEach(value -> tasks.add(CompletableFuture.supplyAsync(CompleteableFuturePerfTest::getJob)));

    long start = System.currentTimeMillis();
    int sum = tasks.stream().map(CompletableFuture::join).mapToInt(Integer::intValue).sum();
    checkSum(sum, jobCount);
    return System.currentTimeMillis() - start;
}

// CompletableFuture 使用自定义的线程池
private static long testCompletableFutureCustomExecutor(int jobCount) {
    ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(200, 200, 5, TimeUnit.MINUTES, new ArrayBlockingQueue<>(100000), new ThreadFactory() {
            @Override
            public Thread newThread(Runnable r) {
                    Thread thread = new Thread(r);
                    thread.setName("CUSTOM_DAEMON_COMPLETABLEFUTURE");
                    thread.setDaemon(true);
                    return thread;
            }
    }, new ThreadPoolExecutor.CallerRunsPolicy());

    List<CompletableFuture<Integer>> tasks = new ArrayList<>();
    IntStream.rangeClosed(1, jobCount).forEach(value -> tasks.add(CompletableFuture.supplyAsync(CompleteableFuturePerfTest::getJob, threadPoolExecutor)));

    long start = System.currentTimeMillis();
    int sum = tasks.stream().map(CompletableFuture::join).mapToInt(Integer::intValue).sum();
    checkSum(sum, jobCount);
    return System.currentTimeMillis() - start;
}

테스트 시스템 구성 : 8 코어 CPU, 메모리 16G

성능 테스트 결과 :

성능 테스트 결과

압력 측정 작업의 큰 번호와 함께 테스트 결과를 볼 수있는 언론에 따르면, 기본 스레드 풀의 성능을 더 사용합니다.

7, CompletableFuture는 확장 :


객체 생성 :

상기 한 방법 supplyAsync 외에도 CompletableFuture은 또한 다음과 같은 방법을 제공한다 :

// 执行任务,CompletableFuture<Void> 无返回值,默认线程池
public static CompletableFuture<Void> runAsync(Runnable runnable) {
      return asyncRunStage(asyncPool, runnable);
}
// 执行任务,CompletableFuture<Void> 无返回值,支持自定义线程池
public static CompletableFuture<Void> runAsync(Runnable runnable,
                                                   Executor executor) {
        return asyncRunStage(screenExecutor(executor), runnable);
}

우리는 매우 다양한 기능을 제공 CompletionStage 인터페이스를 실현, 전투 모드를 CompletableFuture CompletableFuture 언급했다.

CompletionStage 인터페이스는 직렬 관계 풀링 AND 관계 풀링 OR 관계를 지원한다.
이러한 관계에 대한 다음 인터페이스는 사용시 JDK API 자체에 액세스 할 갈 수있는, 간단한 설명이 될 수 있습니다.
한편, 이러한 관계의 각 인터페이스는 비동기 태스크의 실행을위한 대응하는 방법 xxxAsync () 방법을 제공한다.

직렬 관계 :

CompletionStage 설명 직렬 관계, 주로 thenApply, thenRun, thenAccept thenCompose 및 직렬 인터페이스.

소스는 다음과 같이 :

// 对应 U apply(T t) ,接收参数 T并支持返回值 U
public <U> CompletionStage<U> thenApply(Function<? super T,? extends U> fn);
public <U> CompletionStage<U> thenApplyAsync(Function<? super T,? extends U> fn);

// 不接收参数也不支持返回值
public CompletionStage<Void> thenRun(Runnable action);
public CompletionStage<Void> thenRunAsync(Runnable action);

// 接收参数但不支持返回值
public CompletionStage<Void> thenAccept(Consumer<? super T> action);
public CompletionStage<Void> thenAcceptAsync(Consumer<? super T> action);

// 组合两个依赖的 CompletableFuture 对象
public <U> CompletionStage<U> thenCompose
        (Function<? super T, ? extends CompletionStage<U>> fn);
public <U> CompletionStage<U> thenComposeAsync
        (Function<? super T, ? extends CompletionStage<U>> fn);

집계와의 관계 :

수렴 AND 관계를 설명 CompletionStage, thenCombine, thenAcceptBoth runAfterBoth 및 직렬 인터페이스가있다.

(안 비동기 방식) 아래 출처 :

// 当前和另外的 CompletableFuture 都完成时,两个参数传递给 fn,fn 有返回值
public <U,V> CompletionStage<V> thenCombine
        (CompletionStage<? extends U> other,
         BiFunction<? super T,? super U,? extends V> fn);

// 当前和另外的 CompletableFuture 都完成时,两个参数传递给 action,action 没有返回值
public <U> CompletionStage<Void> thenAcceptBoth
        (CompletionStage<? extends U> other,
         BiConsumer<? super T, ? super U> action);

// 当前和另外的 CompletableFuture 都完成时,执行 action
public CompletionStage<Void> runAfterBoth(CompletionStage<?> other,
                                              Runnable action);

집계 OR 관계 :

수렴 OR 관계를 설명 CompletionStage, applyToEither, acceptEither runAfterEither 및 직렬 인터페이스가있다.

(안 비동기 방식) 아래 출처 :

// 当前与另外的 CompletableFuture 任何一个执行完成,将其传递给 fn,支持返回值
public <U> CompletionStage<U> applyToEither
        (CompletionStage<? extends T> other,
         Function<? super T, U> fn);

// 当前与另外的 CompletableFuture 任何一个执行完成,将其传递给 action,不支持返回值
public CompletionStage<Void> acceptEither
        (CompletionStage<? extends T> other,
         Consumer<? super T> action);

// 当前与另外的 CompletableFuture 任何一个执行完成,直接执行 action
public CompletionStage<Void> runAfterEither(CompletionStage<?> other,
                                                Runnable action);

이, CompletableFuture 관련 기능을 통해 소개합니다.

비동기 프로그래밍은 점점 더 성숙, Java 언어의 공식 웹 사이트는 또한 비동기 프로그래밍 모델을 지원하므로 비동기 프로그래밍이 필요 배울 시작.

시나리오 중심의 비즈니스 요구를 결합, 다음 JDK1.8 CompletableFuture가 추가 분석을 수행하는 확장 기능을 사용하여, 핵심 강점, 성능 비교 테스트를 사용하는 방법이며, 미래 디자인 패턴 전투로 이어집니다.

내가 도와주고 싶어!

나는 대중 번호의 관심을 환영합니다 ~ 당신과 함께 성장, 관심을 더 흥미로운 기사를 잠금을 해제하는 두 가지 차원 코드를 스캔
자바 매니아 커뮤니티

추천

출처www.cnblogs.com/ldws/p/11627139.html