web-dev-qa-db-fra.com

Comment implémenter les délais d'expiration des méthodes synchrones en Java?

J'ai un chemin d'exécution synchrone qui doit se terminer ou expirer dans un délai donné. Disons que j'ai une classe avec la méthode main () dans laquelle j'appelle des méthodes A() qui à leur tour appelle B() et cela à son tour appelle C() de classes identiques ou différentes ..... toutes synchrones sans utiliser de ressource externe comme une base de données, un service Web ou un système de fichiers (où chacune d'elles peut être expirée indépendamment à l'aide d'un TxManager ou api de timeout respectives.) C'est donc plus comme un calcul gourmand en CPU ou en mémoire. Comment puis-je coder pour son timeout en Java?

J'ai regardé TimerTask mais plus pour rendre le flux asynchrone et pour planifier des tâches. D'autres suggestions ?

22
Smitesh

Vous devez utiliser ExecutorService pour ce faire

ExecutorService executor = Executors.newSingleThreadExecutor();
Future<String> future = executor.submit(new Callable() {

    public String call() throws Exception {
        //do operations you want
        return "OK";
    }
});
try {
    System.out.println(future.get(2, TimeUnit.SECONDS)); //timeout is in 2 seconds
} catch (TimeoutException e) {
    System.err.println("Timeout");
}
executor.shutdownNow();
41
Tala

Vous pouvez exécuter un thread parallèle qui attendra le délai spécifié et interrompra le thread actuel, puis exécutera A(). Cependant, a, b et c doivent être interruptibles, c'est-à-dire vérifier périodiquement le drapeau d'interruption de thread en cours et lever InterruptedException, sinon cela ne fonctionnera pas

    final Thread current = Thread.currentThread();
    Thread timer = new Thread() {
        public void run() {
            try {
                Thread.sleep(5000);
                current.interrupt();
            } catch (InterruptedException e) {
                // timer stopped
            }
        };
    };
    try {
        A();  // this throws InterruptedException if interrupted by timer
        timer.interrupt(); // no timeout lets stop the timer
    } catch (InterruptedException e) {
        // timeout
    }
2
Evgeniy Dorofeev

Vous ne pouvez pas faire un appel synchrone avec un délai d'attente mais vous pouvez l'émuler à l'aide d'un deuxième thread. Voici un exemple pour ce faire:

package com.ardevco.example;

import Java.util.Random;
import Java.util.concurrent.Callable;
import Java.util.concurrent.ExecutionException;
import Java.util.concurrent.ExecutorService;
import Java.util.concurrent.Executors;
import Java.util.concurrent.Future;
import Java.util.concurrent.TimeUnit;
import Java.util.concurrent.TimeoutException;


class ExceptionThrower {
   public static <R> R throwUnchecked(Throwable t) {
      return ExceptionThrower.<RuntimeException, R> trhow0(t);
   }

   @SuppressWarnings("unchecked")
   private static <E extends Throwable, R> R trhow0(Throwable t) throws E {
      throw (E) t;
   }
}

class TestApplicationException1 extends Exception {
   private static final long serialVersionUID = 1L;

   public TestApplicationException1(String string) {
      super(string);
   }
};

class TestApplicationException2 extends Exception {
   private static final long serialVersionUID = 1L;

   public TestApplicationException2(String string) {
      super(string);
   }
};

class TestApplicationTimeoutException extends Exception {
   private static final long serialVersionUID = 1L;

   public TestApplicationTimeoutException(String string) {
      super(string);
   };
}

public class SynchronousTimeoutTester {

   public static final long SYNC_METHOD_TIMEOUT_IN_MILLISECONDS = 2000L;
   private final ExecutorService executorService = Executors.newSingleThreadExecutor();

   public static void main(String[] args) {
      SynchronousTimeoutTester tester = new SynchronousTimeoutTester();
      /* call the method asynchronously 10 times */
      for (int i = 0; i < 10; i++) {
         try {
            System.out.println("Result sync call: " + tester.getAsynchTest());
         }
         catch (TestApplicationException1 e) {
            System.out.println("catched as TestApplicationException1: " + e);
         }
         catch (TestApplicationException2 e) {
            System.out.println("catched as TestApplicationException2: " + e);
         }
         catch (TestApplicationTimeoutException e) {
            System.out.println("catched as TestApplicationTimeoutException: " + e);
         }
         catch (InterruptedException e) {
            System.out.println("catched as InterruptedException: " + e);
         }
         catch (Exception e) {
            System.out.println("catched as Exception: " + e);
         }
      }

      tester.shutdown();
   }

   private void shutdown() {
      executorService.shutdown();
      try {
         executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
      }
      catch (InterruptedException e) {
         System.out.println("Error stopping threadpool:" + e);
      }
   }

   private Integer testAsynch() throws TestApplicationException1, TestApplicationException2, InterruptedException {
      Random random = new Random();
      switch (random.nextInt(10)) {
         case 0:
            return 0;
         case 1:
            throw new TestApplicationException1("thrown TestApplicationException1");
         case 2:
            throw new TestApplicationException2("thrown TestApplicationException2");
         case 3:
            Thread.sleep(10000L);
            return -1;
         case 4:
            throw new RuntimeException("thrown Exception");
         default:
            return random.nextInt(10);
      }
   }

   private Integer getAsynchTest() throws TestApplicationException1, TestApplicationException2, Exception {
      Integer dummy = null;

      Future<Integer> testAsynchF = executorService.submit(
                                                           new Callable<Integer>() {
                                                              public Integer call() throws Exception {
                                                                 return testAsynch();
                                                              }
                                                           });

      try {
         dummy = testAsynchF.get(SynchronousTimeoutTester.SYNC_METHOD_TIMEOUT_IN_MILLISECONDS, TimeUnit.MILLISECONDS);
      }
      catch (ExecutionException e1) {
         System.out.println("in getAsynchTest: ExecutionException: " + e1);
         ExceptionThrower.throwUnchecked(e1.getCause());
      }
      catch (TimeoutException e1) {
         System.out.println("in getAsynchTest: TimeoutException: " + e1);
         throw new TestApplicationTimeoutException("TimeoutException" + e1);
      }
      catch (InterruptedException e1) {
         System.out.println("in getAsynchTest: InterruptedException: " + e1);
         throw new Exception(e1);
      }

      return dummy;
   }

}
0
Mehmet Erdemsoy