围绕Java操作应用超时控制

我正在使用第三方Java库与REST API进行交互。 REST API有时需要很长时间才能响应,最终导致抛出java.net.ConnectException

我想缩短超时时间,但无法修改第三方库。

我想在调用Java方法时应用某种forms的超时控制,以便我可以确定在什么时候放弃等待。

这与网络超时无直接关系。 我希望能够尝试执行操作,并能够在指定的等待时间后放弃。

以下内容绝不是有效的Java,但在概念上certificate了我想要实现的目标:

 try { Entity entity = new Entity(); entity.methodThatMakesUseOfRestApi(); } catch () { throw TimeoutException(); } 

我推荐Google Guava库中的TimeLimiter 。

没有一般的超时机制对任意操作有效。

虽然…有一个……通过使用Thread.stop(Throwable)。 它有效且线程安全,但当愤怒的暴徒面对你时,你的人身安全处于危险之中。

 // realizable try { setTimeout(1s); // 1 ... any code // 2 cancelTimeout(); // 3 } catch(TimeoutException te) { // if (3) isn't executed within 1s after (1) // we'll get this exception } 

这可能是使用普通Java如何实现这一目标的当前方式:

 public String getResult(final RESTService restService, String url) throws TimeoutException { // should be a field, not a local variable ExecutorService threadPool = Executors.newCachedThreadPool(); // Java 8: Callable callable = () -> restService.getResult(url); // Java 7: // Callable callable = new Callable() { // @Override // public String call() throws Exception { // return restService.getResult(url); // } // }; Future future = threadPool.submit(callable); try { // throws a TimeoutException after 1000 ms return future.get(1000, TimeUnit.MILLISECONDS); } catch (ExecutionException e) { throw new RuntimeException(e.getCause()); } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new TimeoutException(); } } 

您可以使用Timer和TimerTask 。

这是我写的一个实用工具类,除非我错过了什么,否则它应该可以解决问题。 不幸的是,它只能返回通用对象并抛出通用exception。 其他人可能对如何实现这一点有更好的想法。

 public abstract class TimeoutOperation { long timeOut = -1; String name = "Timeout Operation"; public String getName() { return name; } public void setName(String name) { this.name = name; } public long getTimeOut() { return timeOut; } public void setTimeOut(long timeOut) { this.timeOut = timeOut; } public TimeoutOperation (String name, long timeout) { this.timeOut = timeout; } private Throwable throwable; private Object result; private long startTime; public Object run () throws TimeoutException, Exception { Thread operationThread = new Thread (getName()) { public void run () { try { result = doOperation(); } catch (Exception ex) { throwable = ex; } catch (Throwable uncaught) { throwable = uncaught; } synchronized (TimeoutOperation.this) { TimeoutOperation.this.notifyAll(); } } public synchronized void start() { super.start(); } }; operationThread.start(); startTime = System.currentTimeMillis(); synchronized (this) { while (operationThread.isAlive() && (getTimeOut() == -1 || System.currentTimeMillis() < startTime + getTimeOut())) { try { wait (1000L); } catch (InterruptedException ex) {} } } if (throwable != null) { if (throwable instanceof Exception) { throw (Exception) throwable; } else if (throwable instanceof Error) { throw (Error) throwable; } } if (result != null) { return result; } if (System.currentTimeMillis() > startTime + getTimeOut()) { throw new TimeoutException("Operation '"+getName()+"' timed out after "+getTimeOut()+" ms"); } else { throw new Exception ("No result, no exception, and no timeout!"); } } public abstract Object doOperation () throws Exception; public static void main (String [] args) throws Throwable { Object o = new TimeoutOperation("Test timeout", 4900) { public Object doOperation() throws Exception { try { Thread.sleep (5000L); } catch (InterruptedException ex) {} return "OK"; } }.run(); System.out.println(o); } } 
  static final int NUM_TRIES =4; int tried =0; boolean result =false; while (tried < NUM_TRIES && !result) { try { Entity entity = new Entity(); result = entity.methodThatMakesUseOfRestApi(); } catch () { if ( tried == NUM_TRIES) { throw new TimeoutException(); } } tried++; Thread.sleep(4000); }