我正在编写一个程序,它使用 aCompletionService
在一堆不同的对象上运行线程分析,其中每个“分析”都包括接收一个字符串并进行一些计算以给出true
或false
作为答案。我的代码看起来基本上是这样的:
// tasks come from a different method and contain the strings + some other needed info
List<Future<Pair<Pieces,Boolean>>> futures = new ArrayList<>(tasks.size());
for (Task task : tasks) {
futures.add(executorCompletionService.submit(task));
}
ArrayList<Pair<Pieces, Boolean>> pairs = new ArrayList<>();
int toComplete = tasks.size();
int received = 0;
int failed = 0;
while (received < toComplete) {
Future<Pair<Pieces, Boolean>> resFuture = executorCompletionService.take();
received++;
Pair<Pieces, Boolean> res = resFuture.get();
if (!res.getValue()) failed++;
if (failed > 300) {
// My problem is here
}
pairs.add(res);
}
// return pairs and go on to do something else
在标记部分,我的目标是在超过 300 个字符串失败时让它放弃计算,这样我就可以继续进行新的分析,用一些不同的数据再次调用这个方法。问题是,由于CompletionService
再次使用相同的,如果我不以某种方式清除队列,那么工作队列将继续增长,因为我每次使用它时都会不断添加更多(因为在 300 次失败之后,可能仍有许多未处理左字符串)。
我尝试使用类似的方法遍历futures
列表并删除所有未完成的任务futures.foreach(future -> future.cancel(true)
,但是当我下次调用该方法java.util.concurrent.CancellationException
时,当我尝试调用时出现错误resFuture.get()
。
(编辑:似乎即使我调用foreach(future->future.cancel(true))
,但这并不能保证workerQueue
之后实际上是清除的。我不明白为什么会这样。似乎清除队列需要一段时间,并且代码不会等待以便在进行下一次分析之前发生这种情况,因此偶尔get
会在已取消的未来上调用。)
我也尝试过
while (received < toComplete) {
executorCompletionService.take();
received++;
}
清空队列,虽然这行得通,但它几乎不比只运行所有分析快,因此它对效率的影响并不大。
我的问题是是否有更好的方法来清空工作队列,这样当我下次调用此代码时,它就好像CompletionService
又是新的了。
编辑:我尝试过的另一种方法只是设置executorCompletionService = new CompletionService
,它比我的其他解决方案略快,但仍然相当慢,绝对不是好习惯。
PS:也很高兴接受任何其他可能的方式,我不喜欢使用CompletionService
它只是迄今为止我所做的最简单的事情