如何在Java中调用一些阻塞方法?

有没有一个标准的很好的方式来调用一个阻塞方法在Java中超时? 我想能够做到:

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

如果这是有道理的。

谢谢。

你可以使用一个Executor:

 ExecutorService executor = Executors.newCachedThreadPool(); Callable<Object> task = new Callable<Object>() { public Object call() { return something.blockingMethod(); } }; Future<Object> 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 } 

如果future.get在5秒内没有返回,则抛出一个TimeoutExceptionexception。 超时时间可以以秒,分,毫秒或任何在TimeUnit可用的常量单位进行configuration。

有关更多详细信息,请参阅JavaDoc 。

您可以将呼叫包装在FutureTask并使用get()的超时版本。

请参阅http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/FutureTask.html

还有一个针对jcabi-aspects库的AspectJ解决scheme。

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

它不能得到更简洁,但你必须依赖AspectJ,并在你的构build生命周期中引入它,当然。

有一篇文章进一步解释: 限制Java方法执行时间

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

请注意,该停止不推荐,更好的替代方法是设置一些易变的布尔标志,在blockingMethod()内部检查并退出,如下所示:

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

另请参阅Guava的TimeLimiter ,它在幕后使用Executor。

尝试这个。 更简单的解决scheme 保证,如果在时限内没有执行阻止。 该进程将终止并引发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; } } 

例如:

 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 } 

假设blockingMethod只是睡一些毫秒:

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

我的解决scheme是使用wait()并像这样synchronized

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

所以你可以replace

something.blockingMethod(input)

something.blockingMethod(input, 2000)

希望它有帮助。

您需要像GitHub上故障安全项目中的断路器一样。