框架无法取消任务,原因与您无法取消线程相同。出于所有原因,请参阅 Thread.stop() 上的文档。任务可以持有什么锁?它可以与哪些外部资源相关联?所有相同的 Thread.stop() 原因也适用于任务(毕竟,任务在线程下运行。)您需要告诉任务停止,就像告诉线程停止一样。
我管理另一个使用 scatter-gather 技术的 fork/join 项目。我进行取消或短路的方式是,我创建的每个任务都会传递一个对象 (PassObject),该对象具有
protected volatile boolean stop_now = false;
以及停止任务的方法
protected void stopNow() {stop_now = true; }
每个任务都会定期检查 stop_now,当它为 true 时,它会优雅地结束任务。
不幸的是,stop_now 需要是 volatile 的,因为另一个线程要设置它。如果您经常检查,这可能会增加大量开销。
如何在另一个任务中设置此字段有点棘手。我创建的每个任务还包含对其他所有任务的引用数组的引用
int nbr_tasks = nbr_elements / threshold;
// this holds the common class passed to each task
PassObject[] passList = new PassObject[nbr_tasks];
for (int i = 0; i < nbr_tasks; i++)
passList[i] = new PassObject( passList,… other parms);
一旦列表形成,我 fork() passList 中的每个对象。每个 PassObject 都包含对数组 passList 的引用,该数组包含对传递给每个任务的每个对象的引用。因此,每个任务都知道其他所有任务,当一个任务想要取消其他任务时,它只需调用 cancelOthers 方法并引用 passList。
private void cancelOthers (PassObject[] others) {
// tell all tasks to stop
for (int i = 0, max = others.length; i < max; i++)
others[i].stopNow();
如果您使用的是 Java8,那么您可以使用 CountedCompler 类而不是 RecusiveTask 进行分散收集。对于 Java7 或者如果您仍想使用 RecursiveTask,那么递归中的第一个任务需要创建一个 AtomicBoolean 字段 (AtomicBoolean stop_now = new AtomicBoolean(false);) 并在它创建的每个新 RecursiveTask 中包含对该字段的引用。使用递归,你不知道一开始需要多少层任务。
同样,您需要在代码中定期检查布尔值是否为真,如果为真,则优雅地结束任务。
以上只是如何取消的提示。每个应用程序都是不同的。我所做的适用于我的应用程序——但逻辑是相同的。您需要一个任务可以设置并且每个其他任务都可以看到的每个任务中的共同点。
我会添加更多代码,但插入的代码一次只占用一行,不实用。