如何在Java中使用超时调用某些阻塞方法?

jju*_*uma 90 java concurrency

在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.

  • 阻塞方法即使在超时后也会继续运行,对吧? (8认同)
  • 如何将参数传递给blockingMethod()?谢谢! (3认同)

小智 10

您可以将调用包装在一起FutureTask并使用get()的超时版本.

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

  • FutureTask 本身并不是异步的,是吗?就其本身而言,它只是同步执行操作,您需要将其与执行器结合起来以实现异步行为。 (2认同)

Fed*_*ico 8

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

  • 好主意。但该链接已过时。Googlecode 已不再存在..尝试此链接到 [SimpleTimeLimiter](https://guava.dev/releases/20.0/api/docs/com/google/common/util/concurrent/SimpleTimeLimiter.html) (3认同)

Mic*_*l P 8

人们尝试以多种方式实现这一点,这真的很棒。但事实是,没有办法。

大多数开发人员会尝试将阻塞调用放在不同的线程中,并有一个 future 或某个计时器。但是 Java 中没有办法从外部停止线程,更不用说一些非常具体的情况了,比如显式处理线程中断的 Thread.sleep() 和 Lock.lockInterruptically() 方法。

所以实际上你只有 3 个通用选项:

  1. 将阻塞调用放在一个新线程上,如果时间到期,您将继续前进,让该线程挂起。在这种情况下,您应该确保该线程设置为守护程序线程。这样线程就不会阻止您的应用程序终止。

  2. 使用非阻塞 Java API。例如,对于网络,使用 NIO2 并使用非阻塞方法。要从控制台读取,请在阻止等之前使用 Scanner.hasNext() 。

  3. 如果你的阻塞调用不是IO,而是你的逻辑,那么你可以反复检查检查Thread.isInterrupted()是否被外部中断,并thread.interrupt()在阻塞线程上有另一个线程调用

本课程关于并发https://www.udemy.com/java-multithreading-concurrency-performance-optimization/?couponCode=CONCURRENCY

如果您确实想了解 Java 中的工作原理,请真正了解这些基础知识。它实际上讨论了这些特定的限制和场景,以及如何在其中一场讲座中解决它们。

我个人尝试尽可能不使用阻塞调用进行编程。例如,像 Vert.x 这样的工具包可以非常轻松且高效地以非阻塞方式异步执行 IO 和无 IO 操作。

我希望它有帮助