我想就以下问题和解决方案(潜在的)获得您的反馈。
假设有一个Runnable任务,该任务采样CPU使用率并将其写入CSV文件。此任务不会返回任何结果。需要将其安排为永远定期执行。如果用户取消任务,我们将关闭文件编写器,并且用户可以下载CSV文件。
当您将这样的任务提交给ListeningScheduledExecutorService(如下所示)时,您将获得一个ListenableScheduledFuture,它代表任务的结果。
ListenableScheduledFuture<Void> future = (ListenableScheduledFuture<Void>) scheduledExecutorService
.scheduleAtFixedRate(task, initialDelay, interval, timeUnit);
我们注册了一个将来的回调,以便在取消任务后可以下载CSV文件:也就是说,我们需要将ListenableScheduledFuture转换为ListenableScheduledFuture。
Function<Void, File> transformFunc = new Function<Void, File>()
{
@Override
public File apply(Void arg0)
{
return file;
}
};
ListenableScheduledFuture<File> futureToListen = (ListenableScheduledFuture<File>) Futures.transform(future, transformFunc);
// register a callback to the ListenableScheduledFuture<File>
Futures.addCallback(futureToListen, callback, executorService);
注意:根据Guava API DOC 1,取消futureToListen应该导致我们的任务被取消。
问题:
由于任务结果无效,因此如上所示将其强制转换为ListenableScheduledFuture是否有意义?
从语义上讲,将将无效返回的任务的未来转换为某种类型的未来是否有意义?
有没有更好,更优雅的解决方案?使用Java8的CompletableFuture会更好吗?
最佳答案
transform
可能不会做您想要的。您提到取消futureToListen
将取消future
,这是事实。问题是储备金也是如此:取消future
时,futureToListen
也将取消。这将意味着它永远不会计算其结果。
要解决此问题,您有两种选择:
如果您不希望能够取消future
,则将futureToListen
更改为SettableFuture
。然后,取消future
的任何人也会呼叫futureToListen.set(file)
。
如果您确实希望能够取消future
,则将futureToListen
更改为(a)公开AbstractFuture
的set()
(以便您可以执行我在(1)中建议的操作)和(b)实现interruptTask()
呼叫future.cancel()
。
还有其他可能的聪明的解决方案,涉及在future
未成功完成时触发工作,但是我不确定我是否建议这样做。我个人对使用“ Future
已取消”感到有些紧张,因为它表示“工作已成功完成”。例如,这是因为Future
也可以通过执行程序关闭而取消。 (另一个原因:您需要小心区分“在执行过程中引发异常”和“被取消”。)由于这个原因,我建议的解决方案设置为直接调用set()
而不是触发任何取消未来。