为什么Java的scheduleWithFixedDelay使用Runnable而不是FutureTask包装runnable?
使用两个不同的代码示例可以很容易地显示它:
ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
executorService.scheduleWithFixedDelay(new FutureTask<Integer>(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
System.out.println("beep");
return 1;
}
}), 1, 5, TimeUnit.SECONDS);
产生
蜂鸣
但是应用程序没有退出,它似乎只是等待。
但:
ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
executorService.scheduleWithFixedDelay(new Runnable() {
@Override
public void run() {
System.out.println("beep ");
}
}, 1, 5, TimeUnit.SECONDS);
产生
嘟 嘟 嘟 嘟 哔哔
每隔5秒钟。
这里似乎发生了一些我无法确定的锁定。
答案 0 :(得分:13)
因为你有点滥用FutureTask
。
根据Javadocs,FutureTask是“可取消的异步计算”,但更通俗地说,它包含了Runnable / Callable的特定执行以提供异步性。在我刚刚检查之前,我实际上没有意识到它实现了Runnable
- run()
的实现将此Future设置为其计算结果“。
所以在你的第一个例子中发生的是你正在安排未来的任务,它的run方法在1秒后被调用,因此它计算计算的结果(即运行嵌入的Runnable
)。当这个方法退出时,FutureTask现在已经运行并且具有其具体结果 - 因此将来调用run()都是no-ops。
我认为这里的根本问题是直接安排FutureTask似乎没有意义,至少不是你在这里做的方式。如果你想要每五秒钟运行一些代码,那么你绝对应该采用第二种方法。 FutureTask体现了(单个!)计算;你没有理由要多次调用它,事实上它是专门缓存结果来防止这种情况。
答案 1 :(得分:3)
您不应该将FutureTask
个对象传递到ScheduledExecutorService
,您应该传递Runnable
或Callable
,然后返回< / em>你是FutureTask
。 FutureTask
实现Runnable
接口的事实似乎是一个不幸的设计缺陷,允许您将输出作为输入传回。
至于为什么会出现这种行为,可能是组件之间的一些奇怪的交互,可能是未定义的。