多线程为何是Java的未来。获取(超时)不可靠?
未来。get(timeout)在给定的超时之后不会可靠地抛出TimeoutException。这是正常的行为还是我能做点什么让它更可靠?这个测试在我的机器上失败了。但是如果我睡3000而不是2000,它就会过去
public class FutureTimeoutTest {
@Test
public void test() throws
ExecutionException,
InterruptedException {
ExecutorService exec = Executors.newSingleThreadExecutor();
final Callable call = new Callable() {
@Override
public Object call() throws Exception {
try {
Thread.sleep(2000);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
return 0;
}
};
final Future future = exec.submit(call);
try {
future.get(1000, TimeUnit.MILLISECONDS);
fail("expected TimeoutException");
} catch (TimeoutException ignore) {
}
}
}
# 1 楼答案
没有理由期待考试通过。假设您提交任务以供执行,然后等待任务完成,那么在等待
Future#get()
开始之前,任何时间都可能会过去,让任务有足够的时间耗尽睡眠时间并完成在您的例子中,我们可以假设运行在
Executor
中的线程获得焦点,而运行在test()
中的主线程处于等待状态,尽管处于可运行状态。至于所观察到的将提交的任务暂停两秒和三秒之间的差异,我希望您会发现即使三秒都不够的情况,这取决于其他进程在您的计算机上忙着做什么# 2 楼答案
@seh是对的
您期望Java提供通常所说的“实时”行为。除非在实时操作系统上运行的具有实时功能的Java发行版中使用实时库,否则无法可靠地实现这一点
举个例子,像HotSpot这样的现代JVM中的Java线程实现依赖于主机操作系统的本机线程调度器来决定何时运行哪些线程。除非线程调度器特别了解实时截止日期等信息,否则在决定何时运行哪些线程时,它可能会采用“整个系统”的视图。如果系统已加载,任何特定线程都可能无法计划在几秒钟内运行。。。或者更久。。。在阻止其运行的条件(例如等待计时器事件)过去后
还有一个问题是,Java GC可能会导致所有其他线程阻塞
如果您真的需要来自Java的实时行为,它是可用的。例如:
但是,您应该希望更改应用程序,以使用不同的API来实现实时行为
# 3 楼答案
我不得不说,我认为其他两个答案目前对Java并发类的评价太低了。它们不会给你毫秒级的精度(“实时”应用程序所期望的精度),但它们通常做得很好。我使用期货和执行器编写了大规模的商业服务,它们通常在预期时间的10毫秒内工作,即使在负载下也是如此
我已经在MacOS 10.6和WinXP w/Java 1.6.0_22上运行了这个测试,它们都按预期工作
我对代码进行了如下修改,以测试其准确性:
在XP中打印“1.002598934秒后超时”,在MacOS X中打印“1.003158秒后超时”
如果原始海报描述了他们的OS和JDK版本,也许我们可以确定这是否是一个特定的bug