java - 取消 Future 并仍然检索其返回值

标签 java multithreading

我有一个记录器类,它每 n 毫秒轮询一次数据源中的值。整个过程应该异步运行并返回包含记录数据的集合。

我的想法是拥有一个带有单线程的 ExecutorService 和一个进行数据轮询的 Callable。可调用对象应该被中断,因此调用者不必等待任何 Thread.sleep 调用完成。为了中断 Callable,我对从 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();

我在 recorder.getRecordedData() 调用中收到 java.util.concurrent.CancellationException

我猜除了中断线程之外,cancel(true) 还会设置取消标志,因此对 Future.get() 的调用总是会失败。

有没有办法解决这个问题,或者您是否知道更好的替代方案,可以让我中断线程,打破 Thread.sleep() 并仍然能够返回值?

最佳答案

好吧,你要求的东西在概念上没有意义:

让我们引用 get() 的 javadoc :

抛出:CancellationException - 如果计算被取消

对于cancel(),它说:

此方法返回后,后续调用 isDone() 将始终返回 true。如果此方法返回 true,则后续调用 isCancelled() 将始终返回 true。

换句话说:您可能需要某种其他类型的机制。例如,您可以将 Runable 更改为推送已收集的信息而不是返回它。

换句话说:不是使用 Future 在某个时刻获取所有数据;为什么不直接在到达时将所有数据发送到“安全接收器”?你的方法是民意调查;但显然:轮询和中断并不是齐头并进的!

编辑:现在您可以像这样创建记录器:

 public Recorder(DataSource source)

因此您构建了从接收“数据”的功能。一个简单的解决方案可能是

 public Recorder(DataSource source, List<MyData> sink)

还有。

并且无需在 Runable 中保留本地 dataList ...您只需附加到提供给记录器的 sink 即可。

我使用“安全”这个词只是指当多个线程开始更新同一个列表时需要注意的事实。

关于java - 取消 Future 并仍然检索其返回值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41858035/

相关文章:

c++ - 在已经存在的类上调用一个线程而不是创建一个

java - 尝试用 Java 发送请求时出现错误 407

java - Hibernate 只返回一个结果(更改表名后)

android - 为什么我的 c 套接字死了?

java - Java中线程间对象的访问

java - Java 指针写入是原子的吗?

java - 如何从 php 文件获取变量并在 Android Activity 中使用它?

java - 使用 SVNKit checkout 目录/文件

java - 如何在 onCreate 中使用 glide 获取位图?

python - 如何确定正在运行的当前进程是否是父进程?