2012-09-12 10 views
32

Na podstawie przykładów guawy, na których widziałem, szukałem eleganckich rozwiązań mojego problemu. Szczególnie podoba mi się sposób, w jaki działa Futures.addCallback(ListenableFuture, FutureCallback), ale chciałbym móc ustawić limit czasu na czas, który może wygasnąć przed wywołaniem FutureCallback. Optymalnie byłoby miło, gdyby przekroczenie limitu czasu spowodowało awarię FutureCallback.ListenableFuture, FutureCallback i timeout

Czy Guava już coś takiego ma? Czy po prostu nie zaleca się łączenia limitów czasu z odwołaniami?

EDYCJA: W tym przykład kodu, który doprowadził mnie do tego punktu. Oczywiście, usunąłem znaczące bity, aby uzyskać minimalny przykład.

@Test 
public void testFuture() 
{ 
    Callable<Boolean> callable = new Callable<Boolean>() 
    { 

     @Override 
     public Boolean call() throws Exception 
     { 
      while(true); 
     } 
    }; 

    ListenableFuture<Boolean> callableFuture = MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor()).submit(callable); 

    Futures.addCallback(callableFuture, new FutureCallback<Boolean>() 
    { 

     @Override 
     public void onFailure(Throwable arg0) 
     { 
      System.out.println("onFailure:"+arg0); 
     } 

     @Override 
     public void onSuccess(Boolean arg0) 
     { 
      System.out.println("onSuccess:"+arg0); 
     } 
    }); 

    try 
    { 
     callableFuture.get(1000, TimeUnit.MILLISECONDS); 
    }catch(Throwable t) 
    { 
     System.out.println("catch:"+t); 
    } 
} 

Ten kod wyświetli tylko catch:java.util.concurrent.TimeoutException.

Odpowiedz

21

Aktualizacja: Zostało to dodane do Guava jako Futures.withTimeout().


Wewnętrznie mamy makeTimeoutFuture metodę, która pobiera Future jako wejście i zwraca nową Future która będzie miała taki sam rezultat chyba oryginał nie został wypełniony przez danego terminu. Jeśli termin upłynie, wynik Future ma ustawiony wynik na TimeoutException. Można więc zadzwonić pod numer makeTimeoutFuture i dołączyć detektory do wyjścia Future.

makeTimeoutFuture nie jest najbardziej naturalnym rozwiązaniem problemu. W rzeczywistości uważam, że metoda została stworzona przede wszystkim po to, aby ustawić twardy limit czasu dla połączeń no-arg get(), ponieważ może to być ból w propagowaniu pożądanego terminu dla wszystkich dzwoniących. Bardziej naturalnym rozwiązaniem jest uzasadnienie, że get() ma być get(long, TimeUnit) jako addCallback(ListenableFuture, FutureCallback) na addCallback(ListenableFuture, FutureCallback, long, TimeUnit, SchededuledExecutorService). To trochę niezgrabne, ale mniej niż makeTimeoutFuture. Chciałbym poświęcić temu więcej uwagi, zanim popełnię cokolwiek. Czy byłbyś file a feature request?

(Oto co mamy wewnętrznie :)

public static <V> ListenableFuture<V> makeTimeoutFuture(
    ListenableFuture<V> delegate, 
    Duration duration, 
    ScheduledExecutorService scheduledExecutor) 

Zwraca przyszłość, która deleguje do drugiego, ale zakończy się wcześnie (za pomocą TimeoutException zawinięte w ExecutionException) jeżeli upłynie określony czas. Przyszłość uczestnika nie jest w tym przypadku anulowana.

scheduledExecutor.schedule(new Runnable() { 
    @Override public void run() { 
    TimeoutFuture.this.setException(new TimeoutException("Future timed out")); 
    } 
}, duration.getMillis(), TimeUnit.MILLISECONDS); 
+0

Dzięki za zgłoszenie. Otworzyłem prośbę [tutaj] (http://code.google.com/p/guava-libraries/issues/detail?id=1146&thanks=1146&ts=1347504235). –