我有一个记录器类,每n毫秒轮询数据源中的值。整个过程应该异步运行并返回包含记录数据的集合。
我的想法是拥有一个带有单个线程的ExecutorService和一个执行数据轮询的Callable。应该可以调用callable,因此调用者不必等待任何Thread.sleep
调用完成。要中断他可调用我在ExecutorService返回的Future上调用Future.cancel(true)
:
class Recorder {
private DataSource source;
private ExecutorService executor;
private Future<List<MyData>> dataFuture;
private class FixedPollRateCallable {
private DataSource source;
private long pollrate;
public FixedPollrateCallable(DataSource source, long pollrate) {
this.source = source;
this.pollrate = pollrate;
}
public List<MyData> call() throws Exception {
List<MyData> dataList = new ArrayList<>();
while(!Thread.currentThread().isInterrupted()) {
dataList.add(source.getData());
try {
Thread.sleep(pollrate);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
return dataList;
}
}
public Recorder(DataSource source) {
this.source = source;
this.executor = Executors.newSingleThreadExecutor();
}
public void startRecording(long pollrate) {
if(dataFuture != null && !dataFuture.isDone())
throw new RecordingException();
dataFuture = executor.submit(new FixedPollRateCallable(source, pollrate);
}
public void stopRecording() {
dataFuture.cancel(true);
}
public List<MyData> getRecordedData() throws InterruptedException, ExecutionException {
return dataFuture.get();
}
}
但是在调用这样的事情的时候:
recorder.startRecording();
recorder.stopRecording();
recorder.getRecordedData();
我在java.util.concurrent.CancellationException
电话上收到了recorder.getRecordedData()
。
我想除了中断线程外,cancel(true)
还会设置取消标记,因此对Future.get()
的调用将始终失败。
有没有办法,或者你知道一个更好的替代品,允许我打断一个线程,突破Thread.sleep()
并仍然能够返回一个值?
答案 0 :(得分:3)
嗯,你问的是概念上没有意义的东西:
让我们引用get()的javadoc:
抛出:CancellationException - 如果计算被取消
对于cancel()
,它说:
此方法返回后,对isDone()的后续调用将始终返回true。如果此方法返回true,则对isCancelled()的后续调用将始终返回true。
换句话说:你可能需要一些其他类型的机制。例如,您可以将Runable更改为推送已收集的信息,而不是将其返回。
换句话说:在某些时候,不要使用Future来获取所有数据;为什么不直接在抵达时将所有数据发送到“安全水槽”?你的方法是民意调查;但显然:投票和打断不是齐头并进的!
编辑:现在你创建你的记录器:
public Recorder(DataSource source)
所以你构建了从source
接收“数据”。
public Recorder(DataSource source, List<MyData> sink)
。
而不是在您的Runable中保留本地dataList
...您只需附加到提供给记录器的sink
。
我使用“安全”这个词只是指多个线程开始更新相同列表时需要注意的事实。