ListenableFuture, FutureCallback y los tiempos de espera


Basado en los ejemplos de guayaba que he visto he estado buscando soluciones elegantes a mi problema. Específicamente, me gusta la forma Futures.addCallback(ListenableFuture, FutureCallback) funciona, pero me gustaría poder establecer un tiempo de espera en la cantidad de tiempo que puede expirar antes de que se invoque FutureCallback. De manera óptima, sería bueno si el incumplimiento del tiempo de espera solo causó una condición de falla de FutureCallback para ser llamado.

¿La guayaba ya tiene algo como esto? ¿Es simplemente no se recomienda tratar de pareja ¿tiempos de espera con las devoluciones de llamada?

EDITAR: Incluyendo ejemplo del código que me llevó a este punto. Obviamente, eliminé los bits significativos para obtener un ejemplo mínimo.

@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);
    }
}

Este código solo imprimirá catch:java.util.concurrent.TimeoutException.

 33
Author: sebkur, 2012-09-12

1 answers

Update: Esto se ha añadido a Guava como Futures.withTimeout().


Internamente, tenemos un método makeTimeoutFuture que toma un Future como entrada y devuelve un nuevo Future que tendrá el mismo resultado a menos que el original no se haya completado en un plazo determinado. Si el plazo expira, la salida Future tiene su resultado establecido en un TimeoutException. Por lo tanto, podría llamar a makeTimeoutFuture y adjuntar oyentes a la salida Future.

makeTimeoutFuture no es la solución más natural para su problema. En de hecho, creo que el método fue creado principalmente para establecer un tiempo de espera duro en llamadas no-arg get(), ya que puede ser un dolor propagar la fecha límite deseada a todos los que llaman. Una solución más natural es razonar que get() es a get(long, TimeUnit) como addCallback(ListenableFuture, FutureCallback) es a addCallback(ListenableFuture, FutureCallback, long, TimeUnit, SchededuledExecutorService). Eso es un poco torpe, aunque menos que makeTimeoutFuture. Me gustaría pensar más en esto antes de comprometerme con nada. ¿Podría presentar una solicitud de característica?

(Esto es lo que tenemos internamente:)

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

Devuelve un futuro que delega a otro, pero terminará temprano (a través de un TimeoutException envuelto en un ExecutionException) si la duración especificada expira. El futuro delegado no se cancela en este caso.

scheduledExecutor.schedule(new Runnable() {
  @Override public void run() {
    TimeoutFuture.this.setException(new TimeoutException("Future timed out"));
  }
}, duration.getMillis(), TimeUnit.MILLISECONDS);
 23
Author: Chris Povirk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-08-18 15:56:33