Comment appeler une méthode de blocage avec un délai d’attente en Java?

Existe-t-il un moyen simple d’appeler une méthode de blocage avec un délai d’attente en Java? Je veux pouvoir faire:

// call something.blockingMethod(); // if it hasn't come back within 2 seconds, forget it 

si ça a du sens.

Merci.

Vous pouvez utiliser un exécuteur:

 ExecutorService executor = Executors.newCachedThreadPool(); Callable task = new Callable() { public Object call() { return something.blockingMethod(); } }; Future future = executor.submit(task); try { Object result = future.get(5, TimeUnit.SECONDS); } catch (TimeoutException ex) { // handle the timeout } catch (InterruptedException e) { // handle the interrupts } catch (ExecutionException e) { // handle other exceptions } finally { future.cancel(true); // may or may not desire this } 

Si le future.get ne retourne pas dans les 5 secondes, il génère une TimeoutException . Le délai d’attente peut être configuré en secondes, minutes, millisecondes ou toute unité disponible en tant que constante dans TimeUnit .

Voir le JavaDoc pour plus de détails.

Vous pouvez envelopper l’appel dans une FutureTask et utiliser la version de délai d’attente de get ().

Voir http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/FutureTask.html

Il existe également une solution AspectJ pour cela avec la bibliothèque jcabi-aspects .

 @Timeable(limit = 30, unit = TimeUnit.MINUTES) public Soup cookSoup() { // Cook soup, but for no more than 30 minutes (throw and exception if it takes any longer } 

Cela ne peut pas être plus succinct, mais vous devez dépendre de AspectJ et l’introduire dans votre cycle de construction, bien sûr.

Il y a un article expliquant cela plus loin: Temps d’exécution de la méthode Java

Voir aussi TimeLimiter de Guava qui utilise un exécuteur en coulisse.

 Thread thread = new Thread(new Runnable() { public void run() { something.blockingMethod(); } }); thread.start(); thread.join(2000); if (thread.isAlive()) { thread.stop(); } 

Notez que cet arrêt est obsolète, une meilleure alternative est de définir un indicateur booléen volatile, à l’intérieur de blockingMethod (), et de le vérifier, comme ceci:

 import org.junit.*; import java.util.*; import junit.framework.TestCase; public class ThreadTest extends TestCase { static class Something implements Runnable { private volatile boolean stopRequested; private final int steps; private final long waitPerStep; public Something(int steps, long waitPerStep) { this.steps = steps; this.waitPerStep = waitPerStep; } @Override public void run() { blockingMethod(); } public void blockingMethod() { try { for (int i = 0; i < steps && !stopRequested; i++) { doALittleBit(); } } catch (InterruptedException e) { throw new RuntimeException(e); } } public void doALittleBit() throws InterruptedException { Thread.sleep(waitPerStep); } public void setStopRequested(boolean stopRequested) { this.stopRequested = stopRequested; } } @Test public void test() throws InterruptedException { final Something somethingRunnable = new Something(5, 1000); Thread thread = new Thread(somethingRunnable); thread.start(); thread.join(2000); if (thread.isAlive()) { somethingRunnable.setStopRequested(true); thread.join(2000); assertFalse(thread.isAlive()); } else { fail("Exptected to be alive (5 * 1000 > 2000)"); } } } 

Essaye ça. Solution plus simple. Garantit que si le bloc ne s’exécutait pas dans les délais impartis. le processus se terminera et lancera une exception.

 public class TimeoutBlock { private final long timeoutMilliSeconds; private long timeoutInteval=100; public TimeoutBlock(long timeoutMilliSeconds){ this.timeoutMilliSeconds=timeoutMilliSeconds; } public void addBlock(Runnable runnable) throws Throwable{ long collectIntervals=0; Thread timeoutWorker=new Thread(runnable); timeoutWorker.start(); do{ if(collectIntervals>=this.timeoutMilliSeconds){ timeoutWorker.stop(); throw new Exception("< <<<<<<<<<****>>>>>>>>>>> Timeout Block Execution Time Exceeded In "+timeoutMilliSeconds+" Milli Seconds. Thread Block Terminated."); } collectIntervals+=timeoutInteval; Thread.sleep(timeoutInteval); }while(timeoutWorker.isAlive()); System.out.println("< <<<<<<<<<####>>>>>>>>>>> Timeout Block Executed Within "+collectIntervals+" Milli Seconds."); } /** * @return the timeoutInteval */ public long getTimeoutInteval() { return timeoutInteval; } /** * @param timeoutInteval the timeoutInteval to set */ public void setTimeoutInteval(long timeoutInteval) { this.timeoutInteval = timeoutInteval; } } 

Exemple :

 try { TimeoutBlock timeoutBlock = new TimeoutBlock(10 * 60 * 1000);//set timeout in milliseconds Runnable block=new Runnable() { @Override public void run() { //TO DO write block of code } }; timeoutBlock.addBlock(block);// execute the runnable block } catch (Throwable e) { //catch the exception here . Which is block didn't execute within the time limit } 

Supposons que la méthode est juste de dormir pour quelques millis:

 public void blockingMethod(Object input) { try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } } 

Ma solution consiste à utiliser wait() et synchronized comme ceci:

 public void blockingMethod(final Object input, long millis) { final Object lock = new Object(); new Thread(new Runnable() { @Override public void run() { blockingMethod(input); synchronized (lock) { lock.notify(); } } }).start(); synchronized (lock) { try { // Wait for specific millis and release the lock. // If blockingMethod is done during waiting time, it will wake // me up and give me the lock, and I will finish directly. // Otherwise, when the waiting time is over and the // blockingMethod is still // running, I will reacquire the lock and finish. lock.wait(millis); } catch (InterruptedException e) { e.printStackTrace(); } } } 

Donc, vous pouvez remplacer

something.blockingMethod(input)

à

something.blockingMethod(input, 2000)

J’espère que cela aide.

Vous avez besoin d’une implémentation de disjoncteur comme celle présente dans le projet de sécurité sur GitHub.