考虑以下代码:
Thread thread = new Thread(() -> tasks.parallelStream().forEach(Runnable::run));
任务是应该并行执行的Runnable列表。 当我们启动这个线程并开始执行时,根据一些计算,我们需要中断(取消)所有这些任务。
中断线程只会停止其中一个执行。我们如何处理他人?或者Streams不应该那样使用?或者你知道更好的解决方案吗?
答案 0 :(得分:3)
您实际上并未在要创建的线程上运行Runnables。您正在运行将提交到池的线程,因此:
Thread thread = new Thread(() -> tasks.parallelStream().forEach(Runnable::run));
在这个例子中,你做的是较小的术语
List<Runnable> tasks = ...;
Thread thread = new Thread(new Runnable(){
public void run(){
for(Runnable r : tasks){
ForkJoinPool.commonPool().submit(r);
}
}
});
这是因为您在处理并行执行时使用了委托给公共池的parallelStream
。
据我所知,你无法使用parallelStream
来处理正在执行任务的线程,所以可能运气不好。你总是可以做一些棘手的事情来获得这个线程,但这可能不是最好的主意。
答案 1 :(得分:2)
类似以下的内容应该适合您:
AtomicBoolean shouldCancel = new AtomicBoolean();
...
tasks.parallelStream().allMatch(task->{
task.run();
return !shouldCancel.get();
});
方法allMatch
的文档特别指出,“如果不需要确定结果,则可能不对所有元素评估谓词。”因此,如果要取消的谓词不匹配,则无需再进行求值。此外,您可以检查返回结果以查看循环是否已取消。
答案 2 :(得分:1)
您可以使用ForkJoinPool
来中断线程:
@Test
public void testInterruptParallelStream() throws Exception {
final AtomicReference<InterruptedException> exc = new AtomicReference<>();
final ForkJoinPool forkJoinPool = new ForkJoinPool(4);
// use the pool with a parallel stream to execute some tasks
forkJoinPool.submit(() -> {
Stream.generate(Object::new).parallel().forEach(obj -> {
synchronized (obj) {
try {
// task that is blocking
obj.wait();
} catch (final InterruptedException e) {
exc.set(e);
}
}
});
});
// wait until the stream got started
Threads.sleep(500);
// now we want to interrupt the task execution
forkJoinPool.shutdownNow();
// wait for the interrupt to occur
Threads.sleep(500);
// check that we really got an interruption in the parallel stream threads
assertTrue(exc.get() instanceof InterruptedException);
}
工作线程确实被中断,终止阻塞操作。您也可以在shutdown()
内致电Consumer
。
请注意,这些睡眠可能不会针对正确的单元测试进行调整,您可能有更好的想法,只需等待即可。但它足以表明它正在发挥作用。