33 votes

ListenableFuture, FutureCallback et délais d'attente

D'après les exemples de goyave que j'ai vus, j'ai cherché des solutions élégantes à mon problème. Plus précisément, j'aime la façon dont Futures.addCallback(ListenableFuture, FutureCallback) fonctionne, mais j'aimerais pouvoir définir un délai d'attente avant que le FutureCallback ne soit invoqué. De manière optimale, il serait bon que le dépassement du délai entraîne l'appel de la condition d'échec de FutureCallback.

Est-ce que Guava a déjà quelque chose comme ça ? Est-il simplement déconseillé d'essayer de coupler les délais d'attente avec les rappels ?

EDIT : Incluant un exemple du code qui m'a conduit à ce point. Évidemment, j'ai enlevé les parties significatives pour obtenir un exemple minimum.

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

Ce code n'imprimera que catch:java.util.concurrent.TimeoutException .

24voto

Chris Povirk Points 1793

En interne, nous avons un makeTimeoutFuture qui prend un Future en entrée et renvoie un nouveau Future qui aura le même résultat sauf si l'original n'a pas terminé dans un délai donné. Si le délai expire, la sortie Future a son résultat fixé à un TimeoutException . Ainsi, vous pourriez appeler makeTimeoutFuture et attacher des écouteurs à la sortie Future .

makeTimeoutFuture n'est pas la solution la plus naturelle pour votre problème. En fait, je pense que cette méthode a été créée principalement pour fixer un délai d'attente strict pour les requêtes sans argument. get() car il peut être pénible de propager la date limite souhaitée à tous les appelants. Une solution plus naturelle est de raisonner que get() est de get(long, TimeUnit) comme addCallback(ListenableFuture, FutureCallback) est de addCallback(ListenableFuture, FutureCallback, long, TimeUnit, SchededuledExecutorService) . C'est un peu maladroit, mais moins que makeTimeoutFuture . J'aimerais y réfléchir davantage avant de m'engager. Est-ce que vous déposer une demande de fonctionnalité ?

(Voici ce que nous avons en interne :)

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

Retourne un futur qui délègue à un autre mais qui se terminera plus tôt (via un TimeoutException enveloppé dans un ExecutionException ) si la durée spécifiée expire. Le futur délégué n'est pas annulé dans ce cas.

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X