[java] 자바 실행자 : 작업이 완료되면 차단없이 알림을받는 방법?


Answers

Guava의 청취 가능한 향후 API를 사용하고 콜백을 추가하십시오. Cf. 웹 사이트 :

ListeningExecutorService service = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(10));
ListenableFuture<Explosion> explosion = service.submit(new Callable<Explosion>() {
  public Explosion call() {
    return pushBigRedButton();
  }
});
Futures.addCallback(explosion, new FutureCallback<Explosion>() {
  // we want this handler to run immediately after we push the big red button!
  public void onSuccess(Explosion explosion) {
    walkAwayFrom(explosion);
  }
  public void onFailure(Throwable thrown) {
    battleArchNemesis(); // escaped the explosion!
  }
});
Question

집행자 서비스에 제출해야하는 작업으로 가득 찬 대기열이 있다고 가정 해보십시오. 한 번에 하나씩 처리하도록합니다. 내가 생각할 수있는 가장 간단한 방법은 다음과 같습니다.

  1. 대기열에서 작업 가져 오기
  2. 집행자에게 제출하십시오.
  3. 반환 된 Future에서 .get을 호출하고 결과를 사용할 수있을 때까지 차단합니다.
  4. 대기열에서 다른 작업 가져 오기 ...

그러나 완전히 차단하는 것을 피하려고합니다. 한 번에 하나씩 처리해야하는 이러한 대기열이 10,000 개라면 스택 공간이 부족합니다. 대다수는 차단 된 스레드를 계속 보유하게 될 것이기 때문입니다.

내가 원하는 것은 과제를 제출하고 과제가 완료 될 때 호출되는 콜백을 제공하는 것입니다. 콜백 알림을 플래그로 사용하여 다음 작업을 보냅니다. (functionaljava 및 jetlang 분명히 이러한 비 차단 알고리즘을 사용하지만 해당 코드를 이해할 수 없다)

어떻게하면 JDK의 java.util.concurrent를 사용하여, 저 자신의 Executor 서비스를 작성하지 않을 수 있습니까?

(이러한 작업을 제공하는 대기열 자체가 차단 될 수 있지만 나중에 해결해야 할 문제입니다)




FutureTask 클래스를 확장하고 done() 메서드를 재정의 done() 다음 FutureTask 객체를 ExecutorService 추가하여 FutureTask 가 즉시 완료 될 때 done() 메서드가 호출되도록 할 수 있습니다.




도움이되었던 Matt의 대답에 덧붙여서, 여기에 콜백의 사용법을 보여주기위한보다 세련된 예제가 있습니다.

private static Primes primes = new Primes();

public static void main(String[] args) throws InterruptedException {
    getPrimeAsync((p) ->
        System.out.println("onPrimeListener; p=" + p));

    System.out.println("Adios mi amigito");
}
public interface OnPrimeListener {
    void onPrime(int prime);
}
public static void getPrimeAsync(OnPrimeListener listener) {
    CompletableFuture.supplyAsync(primes::getNextPrime)
        .thenApply((prime) -> {
            System.out.println("getPrimeAsync(); prime=" + prime);
            if (listener != null) {
                listener.onPrime(prime);
            }
            return prime;
        });
}

출력은 다음과 같습니다.

    getPrimeAsync(); prime=241
    onPrimeListener; p=241
    Adios mi amigito



CountDownLatch 사용하십시오.

이것은 java.util.concurrent 에서 java.util.concurrent 계속 진행하기 전에 여러 스레드가 실행을 완료 할 때까지 기다리는 방법과 같습니다.

콜백 효과를 얻으려면 약간의 추가 작업이 필요합니다. 즉, CountDownLatch 를 사용하는 별도의 스레드에서이 작업을 직접 처리 한 다음 기다리면 알림이 필요한 모든 내용을 알리는 작업이 계속됩니다. 콜백 (callback) 또는 그와 유사한 어떤 것도 네이티브로 지원하지 않습니다.

편집 : 이제 귀하의 질문을 이해하고, 나는 당신이 너무 멀리, 불필요하게 도달하고 있다고 생각합니다. 일반 SingleThreadExecutor 를 사용하는 경우 모든 작업을 제공하면 기본적으로 대기열이 수행됩니다.




이것은 구아바의 ListenableFuture 사용하여 Pache의 대답을 확장 한 것입니다.

특히 Futures.transform()ListenableFuture 반환하므로 비동기 호출을 연결하는 데 사용할 수 있습니다. Futures.addCallback()void 반환하므로 체인에 사용할 수 없지만 비동기 완료시 성공 / 실패를 처리하는 데 적합합니다.

// ListenableFuture1: Open Database
ListenableFuture<Database> database = service.submit(() -> openDatabase());

// ListenableFuture2: Query Database for Cursor rows
ListenableFuture<Cursor> cursor =
    Futures.transform(database, database -> database.query(table, ...));

// ListenableFuture3: Convert Cursor rows to List<Foo>
ListenableFuture<List<Foo>> fooList =
    Futures.transform(cursor, cursor -> cursorToFooList(cursor));

// Final Callback: Handle the success/errors when final future completes
Futures.addCallback(fooList, new FutureCallback<List<Foo>>() {
  public void onSuccess(List<Foo> foos) {
    doSomethingWith(foos);
  }
  public void onFailure(Throwable thrown) {
    log.error(thrown);
  }
});

참고 : Futures.transform() 을 사용하면 비동기 작업을 체인화하는 것 외에도 별도의 실행 프로그램에서 각 작업을 예약 할 수 있습니다 (이 예제에서는 표시되지 않음).




Related