在Java中使用超时调用阻塞方法是否有一种标准的好方法?我希望能够做到:
// call something.blockingMethod();
// if it hasn't come back within 2 seconds, forget it
Run Code Online (Sandbox Code Playgroud)
如果这是有道理的.
谢谢.
ska*_*man 140
你可以使用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
}
Run Code Online (Sandbox Code Playgroud)
如果future.get在5秒内没有返回,则抛出一个TimeoutException.超时可以以秒,分钟,毫秒或任何可用单位配置为常量TimeUnit.
有关更多详细信息,请参阅JavaDoc.
小智 10
您可以将调用包装在一起FutureTask并使用get()的超时版本.
请参阅http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/FutureTask.html
另请参阅 Guava 的TimeLimiter,它在幕后使用了 Executor。
人们尝试以多种方式实现这一点,这真的很棒。但事实是,没有办法。
大多数开发人员会尝试将阻塞调用放在不同的线程中,并有一个 future 或某个计时器。但是 Java 中没有办法从外部停止线程,更不用说一些非常具体的情况了,比如显式处理线程中断的 Thread.sleep() 和 Lock.lockInterruptically() 方法。
所以实际上你只有 3 个通用选项:
将阻塞调用放在一个新线程上,如果时间到期,您将继续前进,让该线程挂起。在这种情况下,您应该确保该线程设置为守护程序线程。这样线程就不会阻止您的应用程序终止。
使用非阻塞 Java API。例如,对于网络,使用 NIO2 并使用非阻塞方法。要从控制台读取,请在阻止等之前使用 Scanner.hasNext() 。
如果你的阻塞调用不是IO,而是你的逻辑,那么你可以反复检查检查Thread.isInterrupted()是否被外部中断,并thread.interrupt()在阻塞线程上有另一个线程调用
如果您确实想了解 Java 中的工作原理,请真正了解这些基础知识。它实际上讨论了这些特定的限制和场景,以及如何在其中一场讲座中解决它们。
我个人尝试尽可能不使用阻塞调用进行编程。例如,像 Vert.x 这样的工具包可以非常轻松且高效地以非阻塞方式异步执行 IO 和无 IO 操作。
我希望它有帮助