Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/328.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么Java Future.get(超时)不可靠?_Java_Multithreading_Timeout_Java.util.concurrent - Fatal编程技术网

为什么Java Future.get(超时)不可靠?

为什么Java Future.get(超时)不可靠?,java,multithreading,timeout,java.util.concurrent,Java,Multithreading,Timeout,Java.util.concurrent,Future.get(timeout)在给定超时后不会可靠地抛出TimeoutException。这是正常的行为还是我能做点什么让它更可靠?这个测试在我的机器上失败了。但是如果我睡3000而不是2000,它就会过去 public class FutureTimeoutTest { @Test public void test() throws ExecutionException, InterruptedException { ExecutorService exec

Future.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) {
    }
}

}没有理由期望考试通过。假设您提交任务以供执行,然后等待任务完成,那么在等待
Future\get()
开始之前,任何时间都可能会过去,从而使任务有足够的时间耗尽睡眠时间并完成

在您的情况下,我们可以假设在
执行器中运行的线程获得焦点,而运行
test()
的主线程处于等待状态,尽管处于可运行状态。至于所观察到的将提交的任务暂停2秒和3秒之间的差异,我希望您会发现即使3秒也不够用的情况,这取决于您的计算机上其他进程正在忙什么。

@seh是正确的

您期望从Java获得通常称为“实时”的行为。除非在实时操作系统上运行的具有实时功能的Java发行版中使用实时库,否则无法可靠地实现这一点

举个例子,像HotSpot这样的现代JVM中的Java线程实现依赖于主机操作系统的本机线程调度程序来决定何时运行哪些线程。除非线程调度器特别了解实时截止日期和其他信息,否则在决定何时运行哪些线程时,它可能会采用“整个系统”的视图。如果系统已加载,任何特定线程都可能无法计划在几秒钟内运行。。。或者更久。。。在阻止其运行的条件(例如等待计时器事件)过去后

还有一个问题是,javagc可能会导致所有其他线程阻塞

如果您确实需要来自Java的实时行为,它是可用的。例如:

  • 这一页
  • 维基百科页面

但是,您应该希望更改应用程序以使用不同的API来提供实时行为。

我必须说,我认为其他两个答案目前对Java并发类的评价不太高。它们不会给你毫秒级的精度(“实时”应用程序所期望的精度),但它们通常做得很好。我使用期货和执行器编写了大型商业服务,它们通常在预期时间的10毫秒内工作,即使在负载下也是如此

我已经在MacOS 10.6和WinXP w/Java 1.6.0_22上运行了这个测试,它们都按预期工作

我对代码进行了如下修改,以测试其准确性:

    long time1 = System.nanoTime();

    System.out.println("Submitting");
    final Future<Object> future = exec.submit(call);
    try {
        future.get(1000, TimeUnit.MILLISECONDS);

        long time2 = System.nanoTime();
        System.out.println("No timeout after " + 
                             (time2-time1)/1000000000.0 + " seconds");

        fail("expected TimeoutException");
    } catch (TimeoutException ignore) {
        long time2 = System.nanoTime();
        System.out.println("Timed out after " +
                             (time2-time1)/1000000000.0 + " seconds");
    }
    finally {
        exec.shutdown();
    }
longtime1=System.nanoTime();
系统输出打印项次(“提交”);
最终未来=执行提交(调用);
试一试{
get(1000,时间单位毫秒);
longtime2=System.nanoTime();
System.out.println(“在”+
(时间2-1)/100000000.0+“秒”);
失败(“预期超时异常”);
}捕获(TimeoutException忽略){
longtime2=System.nanoTime();
System.out.println(“之后超时”+
(时间2-1)/100000000.0+“秒”);
}
最后{
exec.shutdown();
}
在XP中打印“1.002598934秒后超时”,在MacOS X中打印“1.003158秒后超时”


如果原始海报描述了他们的操作系统和JDK版本,也许我们可以确定这是否是一个特定的bug。

有趣。月台不同吗?这可能是JVM或操作系统中的一个bug。我不确定这是否真的算作bug。在启动另一个线程到开始等待未来完成之间的时间间隔上,肯定会有一些不确定性。是的,1秒似乎有点多,但我在文档中没有看到任何关于截止日期的硬性保证。我只在Windows XP上试用过。我同意可能存在非决定论,但是在这个例子中没有太多发生。我的实际案例有多个线程,JNI中存在对网络响应的阻塞。在这种情况下,我可以理解超时的一些变化,但在这里?您使用的是什么JVM/JDK/IDE/TestFramework?这在Sun JDK6+jUnit4+Netbeans中运行良好。@Seh指出这可能是一个线程争用问题:如果使用
FutureTask
,将测试更改为在单个线程中运行,会发生什么情况?请尝试在加载的系统上运行该测试,看看它是否准确。在好的一天它能工作,在坏的一天它不能,所以不要编写应用程序(或单元测试)来依赖它。@Stephen-C-当然,我不会依赖于在生产应用程序中总是获得完美的计时,但实际上,我在一个非常大的网络公司中使用过这样的代码用于时间关键型服务,并且在至少99.9%的情况下,它能按要求运行(我们有大约50毫秒的安全余量)。我在Mac OSX 10.6.5和Java 1.6上试过它,它可以正常工作。在办公室里,我使用的是Windows XP Sun Java 1.6-不确定小版本,但它是相当最新的。这在周五是失败的。我确实注意到,我的实际代码在大多数情况下都会出现这种不可靠的超时,但我确实有一天超时会在未来指定的时间的几毫秒内发生。get()。感谢大家的讨论。我的系统可以处理超时的变化(我想)。它是断路器模式的一种实现。只要超时最终发生,断路器至少会增加值。我将等到这段代码进入性能测试环境,看看那里发生了什么。很高兴看到它像@andrewmu的系统一样运行……作为参考,我提到的系统是在Re上运行的