2016-11-03 19 views
2

Java에서 CompletableFuture를 사용할 때 문제가 있습니다. 서버에서 응답을받을 때 채워지는 2 개의 선택 요청이 있습니다.Java CompletableFuture.complete() block

if(hasException) { 
    selectFuture.completeExceptionally(new ClientException(errorCode)); 
} else { 
    System.out.println("Before complete future"); 
    selectFuture.complete(result); 
    System.out.println("After complete future"); 
} 

을 그리고 다른 스레드 (thread에-2), 내가 사용 : 연결 스레드에서

(THREAD-1) (사용 반응기), 내가 사용

CompleteFuture.allOf(allSelect).whenComplete((aVoid, throwable) -> { 
    System.out.println("Receive all future"); 
    // Do sth here 
}); 

내 상황을 시스템이 "Receive all future"를 인쇄하지만 future.complete(result);을 호출하면 THREAD-1이 차단된다는 것입니다.이 명령에서 빠져 나올 수는 없습니다. THREAD-2에서 CompletableFuture.allOf(allOfSelect).get()을 사용하면 THREAD-1이 올바르게 실행됩니다. 하지만 CompletableFuture.get()을 사용하면 성능이 저하되므로 CompletableFuture.whenComplete()을 사용하고 싶습니다.

누구든지 차단의 원인을 설명 할 수 있습니까?

감사합니다.

답변

2

complete 호출은 모두 CompletionStage에 종속됩니다.

이전에 BiConsumerwhenComplete으로 등록한 경우 complete이 호출 스레드에서 호출합니다. 귀하의 경우 complete으로 전화하면 이 (가) whenComplete으로 전달되면 반환됩니다. 이것은 은 현재 CompletableFuture이 완료되거나 완료 방법의 다른 호출자 스레드에 의해 수행 될 수있는 비 비동기 방식의 종속 달성을 위해 제공된 상기 class javadoc

동작에 대하여 설명한다.

(다른 발신자에 의해 whenComplete를 호출하는 스레드가 실제로 적용됩니다 반대의 상황을있는 BiConsumerCompletableFuture이 이미 완료되었다 대상의 경우.)

는 여기를 설명하는 작은 프로그램입니다 행동 :

public static void main(String[] args) throws Exception { 
    CompletableFuture<String> future = new CompletableFuture<String>(); 
    future.whenComplete((r, t) -> { 
     System.out.println("before sleep, executed in thread " + Thread.currentThread()); 
     try { 
      Thread.sleep(5000); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
     System.out.println("after sleep, executed in thread " + Thread.currentThread()); 
    }); 

    System.out.println(Thread.currentThread()); 
    future.complete("completed"); 
    System.out.println("done"); 
} 

이 인쇄됩니다

Thread[main,5,main] 
before sleep, executed in thread Thread[main,5,main] 
after sleep, executed in thread Thread[main,5,main] 
done 

BiConsumer이 메인 스레드 인 complete에 적용된 것을 나타냅니다.

whenCompleteAsync을 사용하면 BiConsumer을 별도의 스레드에서 강제로 실행할 수 있습니다.

는 [...] 즉,이 단계가 완료되면이 단계의 기본 비동기 실행 기능을 이용하여 특정 동작 을 실행한다.

public static void main(String[] args) throws Exception { CompletableFuture<String> future = new CompletableFuture<String>(); CompletableFuture<?> done = future.whenCompleteAsync((r, t) -> { System.out.println("before sleep, executed in thread " + Thread.currentThread()); try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("after sleep, executed in thread " + Thread.currentThread()); }); System.out.println(Thread.currentThread()); future.complete("completed"); System.out.println("done"); done.get(); } 

BiConsumer이 별도의 쓰레드 적용되었음을 나타내는

Thread[main,5,main] 
done 
before sleep, executed in thread Thread[ForkJoinPool.commonPool-worker-1,5,main] 
after sleep, executed in thread Thread[ForkJoinPool.commonPool-worker-1,5,main] 

인쇄한다 예

.

+0

정말 고마워요. 귀하의 설명은 스레딩에 대해 매우 분명합니다. CompletableFuture를 처음 사용하는 경우에는 클라이언트에서 서버로 SELECT, UPDATE 등의 단일 요청을 호출하는 용도로만 사용하므로 클라이언트가 내 기대치 (클라이언트가 응답을 기다리고 미래를 채울 때까지)로 완벽하게 실행됩니다. 하지만 지금은 TRANSACTION을 수행하는 데 문제가 있습니다. 왜냐하면 단계가 있기 때문입니다. 모든 SELECT가 끝난 후에 CompletableFuture로 즉시 미래를 반환하고 싶지만 다른 실행 (UPDATE, DELETE)에 결과가있을 때만 미래가 채워집니다. 사슬에서 물건을 처리 할 수있는 해결책을 제안 해 줄 수 있습니까? 많은 감사! –

+0

다음과 같은 순서로 작업하고 싶습니다. 1. SELECT -> CompletableFuture 2. PREPARE -> CompletableFuture (다른 호출도 CompletableFutures를 반환합니다). 3. COMMIT -> CompletableFuture 및 등록시 등록자가 즉시 트랜잭션을 반환해야합니다. 많은 감사! –