비동기 프로그래밍 Java8 학습

비동기 프로그래밍

소위 비동기가 실제로 호출 된 함수의 반환 값을 기다리지 않고 달성, 운영자가 운영 방법을 계속 할 수 있습니다

작업과 임무를 만들기

어떤 기준이 만들어지지 않습니다

 CompletableFuture<String> noArgsFuture = new CompletableFuture<>();

수신 해당 작업, 더 리턴 값 없습니다

runAsync비동기 계산 방법은 백그라운드에서 수행하지만,이 때의 값을 반환하지 않을 수있다. 그는 보유하고 Runnable목표를.

CompletableFuture noReturn = CompletableFuture.runAsync(()->{
    //执行逻辑,无返回值
});

의무에 들어오는 해당 작업 복귀

이 시점에서 우리는 반환이 볼 CompletableFuture<T>여기 T당신이 반환 값을 원하는 입력합니다. 어떤 Supplier<T>간단한 함수 인터페이스입니다.

CompletableFuture<String> hasReturn = CompletableFuture.supplyAsync(new Supplier<String>() {
    @Override
    public String get() {
        return "hasReturn";
    }
});

이 때, 당신은 사용할 수 있습니다 lambda위의 논리가 더 명확 식을

CompletableFuture<String> hasReturnLambda = CompletableFuture.supplyAsync(TestFuture::get);

private static String get() {
    return "hasReturnLambda";
}

반환 값을 가져옵니다

비동기 작업은 또한 우리가 비동기 작업의 반환 값을 사용하고자 할 때, 우리는 호출 할 수 있습니다, 반환 값이 완료 비동기 작업 값을 반환 할 때까지 수행 차단.CompletableFutureget()

우리는 위의 것입니다 get()방법은 10 초 일시 정지하게 모양을 변형.

그런 다음 전화

public static void main(String[] args) throws ExecutionException, InterruptedException {
    CompletableFuture<String> funtureHasReturnLambda = (CompletableFuture<String>) getFuntureHasReturnLambda();
    System.out.println("Main Method Is Invoking");
    funtureHasReturnLambda.get();
    System.out.println("Main Method End");
}

당신은 다음과 같은 출력 만 호출 볼 수있는 get()방법이 때, 현재의 thread 차단됩니다.

Main Method Is Invoking
Begin Invoke getFuntureHasReturnLambda
End Invoke getFuntureHasReturnLambda
Main Method End

사용자 정의 반환 값

비동기 작업을 기다리는뿐만 아니라 우리가 어떤 시간에 호출 할 수 이외의 값 반환 complete()반환 값을 사용자 정의하는 방법을.


CompletableFuture<String> funtureHasReturnLambda = (CompletableFuture<String>) getFuntureHasReturnLambda();
System.out.println("Main Method Is Invoking");
new Thread(()->{
    System.out.println("Thread Is Invoking ");
    try {
        Thread.sleep(1000);
        funtureHasReturnLambda.complete("custome value");
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    System.out.println("Thread End ");
}).run();
String value = funtureHasReturnLambda.get();
System.out.println("Main Method End value is "+ value);

우리는 비동기 방식의 세트는 10 초 대기하는 비동기 방식은 새로운 스레드를 개시 한 잠깐 이때 경우, 10 초 동안 기다려야하기 때문에, 물론, 이것이 새로운 스레드 출력값의 출력을 볼 수 있고, 그 출력값은 비동기 방식 인 의 값.

Main Method Is Invoking
Begin Invoke getFuntureHasReturnLambda
Thread Is Invoking 
Thread End 
Main Method End value is custome value

순서 비동기 작업을 수행

비동기 작업에 의존 할 필요가 전에 완료 완전한 비동기 작업이있는 경우, 다음 방법을 쓰기? 그것은 호출하는 것입니다 get()미래의 메소드 반환 값을 후 실행? 나는 몇 가지 문제가 쓴 CompletableFuture 우리는 약간의 비동기 작업 순서 요구 사항을 수행하기 위해 원하는 것을 달성하기 위해 우리를 위해하는 방법을 제공한다. thenApply , thenAccept , thenRun 이 세 가지 방법. 이러한 세 가지 방법의 차이이다.

메소드 이름 당신은 작업의 반환 값 전에받을 수 있는지 여부 반환 값이 있습니까
thenApply 당신은 얻을 수 있습니다 있다
thenAccept 당신은 얻을 수 있습니다 아니오
thenRun 사용할 수 없음 아니오

그래서, 일반적으로 thenAccept , thenRun 이 두 가지 방법은 호출 체인의 맨 끝에 사용했다. 다음으로 우리는 예를 느끼는 실제를 사용합니다.


 

정보는 다음과 같이 반환

seqFutureOne seqFutureTwo
seqFutureOnethenAccept
-------------
null
-------------
thenRun
null

차이 thenApply 및 thenApplyAsync

우리는 접미사 이러한 세 가지 방법을 찾을 수 있습니다 Async예를 들어, 방법 thenApplyAsync. 너무 Async접미사 다르지 않고 방법과 방법은? 우리는에있는 thenApply그리고 thenApplyAsync 두 가지 방법을 비교 하였다, 다른 하나는 동일합니다.

이 두 방법의 차이는 사람이 사용하는 경우,이 작업을 수행하려고한다 thenApplyAsync ,에서 실행의 쓰레드 ForkJoinPool.commonPool()경우 실행을위한 다른 스레드를 얻을 thenApply 경우 생성, supplyAsync방법은 매우 빠르게 수행 한 후 thenApply 작업을 실행하는 경우, 주 스레드 실행입니다 그리고, 다음에 특히 느리다 supplyAsync 동일한 스레드를 수행한다. 다음으로 사용 된 예를 보면 sleep, 반응 방식으로 supplyAsync고속 실행 속도.

//thenApply和thenApplyAsync的区别
System.out.println("-------------");
CompletableFuture<String> supplyAsyncWithSleep = CompletableFuture.supplyAsync(()->{
    try {
        Thread.sleep(10000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    return "supplyAsyncWithSleep Thread Id : " + Thread.currentThread();
});
CompletableFuture<String> thenApply = supplyAsyncWithSleep
        .thenApply(name -> name + "------thenApply Thread Id : " + Thread.currentThread());
CompletableFuture<String> thenApplyAsync = supplyAsyncWithSleep
        .thenApplyAsync(name -> name + "------thenApplyAsync Thread Id : " + Thread.currentThread());
System.out.println("Main Thread Id: "+ Thread.currentThread());
System.out.println(thenApply.get());
System.out.println(thenApplyAsync.get());
System.out.println("-------------No Sleep");
CompletableFuture<String> supplyAsyncNoSleep = CompletableFuture.supplyAsync(()->{
    return "supplyAsyncNoSleep Thread Id : " + Thread.currentThread();
});
CompletableFuture<String> thenApplyNoSleep = supplyAsyncNoSleep
        .thenApply(name -> name + "------thenApply Thread Id : " + Thread.currentThread());
CompletableFuture<String> thenApplyAsyncNoSleep = supplyAsyncNoSleep
        .thenApplyAsync(name -> name + "------thenApplyAsync Thread Id : " + Thread.currentThread());
System.out.println("Main Thread Id: "+ Thread.currentThread());
System.out.println(thenApplyNoSleep.get());
System.out.println(thenApplyAsyncNoSleep.get());

우리는 출력되는 것을 알 수 있습니다

-------------
Main Thread Id: Thread[main,5,main]
supplyAsyncWithSleep Thread Id : Thread[ForkJoinPool.commonPool-worker-1,5,main]------thenApply Thread Id : Thread[ForkJoinPool.commonPool-worker-1,5,main]
supplyAsyncWithSleep Thread Id : Thread[ForkJoinPool.commonPool-worker-1,5,main]------thenApplyAsync Thread Id : Thread[ForkJoinPool.commonPool-worker-1,5,main]
-------------No Sleep
Main Thread Id: Thread[main,5,main]
supplyAsyncNoSleep Thread Id : Thread[ForkJoinPool.commonPool-worker-2,5,main]------thenApply Thread Id : Thread[main,5,main]
supplyAsyncNoSleep Thread Id : Thread[ForkJoinPool.commonPool-worker-2,5,main]------thenApplyAsync Thread Id : Thread[ForkJoinPool.commonPool-worker-2,5,main]

당신이 볼 수있는 supplyAsync실행의 방법이 느린, 다음 thenApply메소드 실행 스레드와 supplyAsync 동일한 실행 스레드, 경우 supplyAsync 실행 속도, 다음의 방법을 thenApply실행 방법 스레드와 Main동일한 스레드를 수행하는 방법.

조합 CompletableFuture

CompletableFuture개의 방법과 함께 결합

  1. thenCompose(): 첫 번째 작업은 제 2 동작을 수행 완료되면
  2. thenCombine(): 두 개의 비동기 작업이 완료 될 때 어떤 동작을 수행합니다

thenCompose () 사용

두 번째 타이머 작업이 시간 초과 작업의 반환 값의 사용을 필요로하는 경우 우리는 두 개의 비동기 작업을 정의합니다.

public static CompletableFuture<String> getTastOne(){
    return CompletableFuture.supplyAsync(()-> "topOne");
}

public static CompletableFuture<String> getTastTwo(String s){
    return CompletableFuture.supplyAsync(()-> s + "  topTwo");
}

우리는 사용 thenCompose()의 준비 방법

CompletableFuture<String> thenComposeComplet = getTastOne().thenCompose(s -> getTastTwo(s));
System.out.println(thenComposeComplet.get());

출력은

topOne  topTwo

이전 기억한다면 thenApply()방법, 그것은이 활용하려는 should'll thenApply()방법도 유사한 기능을 달성 할 수있다.

//thenApply
CompletableFuture<CompletableFuture<String>> thenApply = getTastOne()
        .thenApply(s -> getTastTwo(s));
System.out.println(thenApply.get().get());

그러나, 우리는 반환 형식이 중첩 반환 것을 발견, 최종 반환 값을 얻으려면 두 번 호출 할 필요가get()

thenCombine () 사용

이 경우, 예를 들어, 우리는 두 개의 값을 계산해야하고, 비동기 방법을 반환합니다. 이 두 비동기 방식의 경우를 계산하기 위해 수행되어야 합산 동작을 제한 값이었다 그래서 우리가 사용할 수있는 thenCombine()계산 방법.

CompletableFuture<Integer> thenComposeOne = CompletableFuture.supplyAsync(() -> 192);
CompletableFuture<Integer> thenComposeTwo = CompletableFuture.supplyAsync(() -> 196);
CompletableFuture<Integer> thenComposeCount = thenComposeOne
        .thenCombine(thenComposeTwo, (s, y) -> s + y);
System.out.println(thenComposeCount.get());

이 때, thenComposeOne 그리고 thenComposeTwo 그것을 완료 통과에 호출 될 thenCombine 콜백 방법.

여러 CompletableFuture 결합

위에서 우리는 사용 thenCompose()하고 thenCombine()이 두 가지 방법은 CompletableFuture 우리가 임의의 수를 원한다면, 조립 CompletableFuture 함께 조합을? 다음과 같은 두 가지 방법이 결합 될 수있다 사용할 수 있습니다.

  • allOf()모든 기다립니다 CompletableFuture 실행할 콜백 함수 후 소진
  • anyOf(): 즉시 하나 같이 CompletableFuture 완료, 그것은 콜백 함수를 실행합니다. 이 시간에 다른 작업이 수행되지 않습니다.

사용의 다음 쇼는 두 가지 방법

//allOf()
CompletableFuture<Integer> one = CompletableFuture.supplyAsync(() -> 1);
CompletableFuture<Integer> two = CompletableFuture.supplyAsync(() -> 2);
CompletableFuture<Integer> three = CompletableFuture.supplyAsync(() -> 3);
CompletableFuture<Integer> four = CompletableFuture.supplyAsync(() -> 4);
CompletableFuture<Integer> five = CompletableFuture.supplyAsync(() -> 5);
CompletableFuture<Integer> six = CompletableFuture.supplyAsync(() -> 6);

CompletableFuture<Void> voidCompletableFuture = CompletableFuture.allOf(one, two, three, four, five, six);
voidCompletableFuture.thenApply(v->{
    return Stream.of(one,two,three,four, five, six)
            .map(CompletableFuture::join)
            .collect(Collectors.toList());
}).thenAccept(System.out::println);

CompletableFuture<Void> voidCompletableFuture1 = CompletableFuture.runAsync(() -> {
    try {
        Thread.sleep(1000);
    } catch (Exception e) {

    }
    System.out.println("1");
});

우리는 여섯 정의 된 CompletableFuture 모든 대기 CompletableFuture후 다음 출력의 값을 모든 작업의 완료를 기다리고.

anyOf()용법

CompletableFuture<Void> voidCompletableFuture1 = CompletableFuture.runAsync(() -> {
try {
    Thread.sleep(1000);
} catch (Exception e) {

}
System.out.println("voidCompletableFuture1");
});

CompletableFuture<Void> voidCompletableFutur2 = CompletableFuture.runAsync(() -> {
try {
    Thread.sleep(2000);
} catch (Exception e) {

}
System.out.println("voidCompletableFutur2");
});

CompletableFuture<Void> voidCompletableFuture3 = CompletableFuture.runAsync(() -> {
try {
    Thread.sleep(3000);
} catch (Exception e) {

}
System.out.println("voidCompletableFuture3");
});

CompletableFuture<Object> objectCompletableFuture = CompletableFuture
    .anyOf(voidCompletableFuture1, voidCompletableFutur2, voidCompletableFuture3);
objectCompletableFuture.get();

여기서 우리는 세 가지 정의 CompletableFuture시간이 걸리는 작업이 시간 먼저 CompletableFuture완료 할 첫 번째 일 것이다. 다음과 같이 인쇄 결과입니다.

voidCompletableFuture1

예외 처리

우리가 이해 CompletableFuture 하는 방법 비동기 실행, 얼마나 다른 조합 CompletableFuture 순서를 실행하는 방법을 CompletableFuture . 그래서 다음 중요한 단계는 비동기 작업의 구현에서 발생 할 그럼 어떻게, 이상이된다. 다음의 예제를 만들어 보자.


CompletableFuture.supplyAsync(()->{
    //发生异常
    int i = 10/0;
    return "Success";
}).thenRun(()-> System.out.println("thenRun"))
.thenAccept(v -> System.out.println("thenAccept"));

CompletableFuture.runAsync(()-> System.out.println("CompletableFuture.runAsync"));


결과의 구현, 우리는 한 예외가 발생 체인 실행이있는 한, 그 다음 체인도 수행되지 않지만 다른 주 흐름에서 발견 CompletableFuture여전히 실행됩니다.

CompletableFuture.runAsync

예외적으로 ()

우리는 사용할 수 exceptionally이상 치료를

//处理异常

CompletableFuture<String> exceptionally = CompletableFuture.supplyAsync(() -> {
    //发生异常
    int i = 10 / 0;
    return "Success";
}).exceptionally(e -> {
    System.out.println(e);
    return "Exception has Handl";
});
System.out.println(exceptionally.get());

비정상 값이 상기 수신 된 정보에서 발견 될 수있는 다음 인쇄, 지정 반환 값을 반환 할 수있다.

java.util.concurrent.CompletionException: java.lang.ArithmeticException: / by zero
Exception has Handl

핸들()

통화 handle()방법은 예외 및 사용자 정의 반환 값을 캡처 할 수 있습니다, 그의 exceptionally()방법은 조금 다르다 handle()만들어 더 이상 호출되지 않습니다 여부, 방법. 다음 예는

System.out.println("-------有异常-------");
CompletableFuture.supplyAsync(()->{
    //发生异常
    int i = 10/0;
    return "Success";
}).handle((response,e)->{
    System.out.println("Exception:" + e);
    System.out.println("Response:" + response);
    return response;
});

System.out.println("-------无异常-------");
CompletableFuture.supplyAsync(()->{
    return "Sucess";
}).handle((response,e)->{
    System.out.println("Exception:" + e);
    System.out.println("Response:" + response);
    return response;
});

더 이상이 발생하지 않는 경우 우리가 볼 수있는 인쇄 handle()방식이라고도

-------有异常-------
Exception:java.util.concurrent.CompletionException: java.lang.ArithmeticException: / by zero
Response:null
-------无异常-------
Exception:null
Response:Sucess

소스 주소

참조 기사

추천

출처www.cnblogs.com/java1024/p/11354351.html