비동기 프로그래밍
소위 비동기가 실제로 호출 된 함수의 반환 값을 기다리지 않고 달성, 운영자가 운영 방법을 계속 할 수 있습니다
작업과 임무를 만들기
어떤 기준이 만들어지지 않습니다
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";
}
반환 값을 가져옵니다
비동기 작업은 또한 우리가 비동기 작업의 반환 값을 사용하고자 할 때, 우리는 호출 할 수 있습니다, 반환 값이 완료 비동기 작업 값을 반환 할 때까지 수행 차단.CompletableFuture
get()
우리는 위의 것입니다 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
이 두 가지 방법은 호출 체인의 맨 끝에 사용했다. 다음으로 우리는 예를 느끼는 실제를 사용합니다.
![](https://img2018.cnblogs.com/blog/1246845/201908/1246845-20190814200006772-1749287002.png)
정보는 다음과 같이 반환
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
개의 방법과 함께 결합
thenCompose()
: 첫 번째 작업은 제 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