在Java 7+ ForkJoinPool中,是否可以取消任务和所有子任务?

时间:2014-05-26 11:26:52

标签: java java.util.concurrent fork-join

我的程序通过分而治之的方法搜索问题的解决方案(任何解决方案),使用递归和RecursiveTasks实现:我为第一个分支执行任务除法,然后递归到第二个分支:如果第二个分支找到了解,那么我取消第一个分支,否则我等待它的结果。

这可能不是最佳选择。如果找到解决方案,一种方法是针对任何已启动的任务抛出异常。但是,我将如何取消所有已启动的任务?取消任务是否也取消所有子任务?

2 个答案:

答案 0 :(得分:2)

由于无法取消线程的原因,框架无法取消任务。有关所有原因,请参阅Thread.stop()上的文档。任务可以锁定什么锁?它可以与哪些外部资源联系起来?所有相同的Thread.stop()原因也适用于任务(毕竟,任务在线程下运行。)您需要告诉任务停止,就像告诉线程停止一样。

我管理另一个使用分散 - 聚集技术的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);

一旦形成列表,我在passList中fork()每个对象。每个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中包含对该字段的引用。使用递归,您不知道在开始时您需要多少级别的任务。 同样,您需要在代码中定期检查布尔值中的true,如果为true,则优雅地结束任务。

以上只是一个如何取消的提示。每个应用程序都不同。我的工作对我的应用程序有效 - 但逻辑是一样的。在任务可以设置的每个任务中都需要一些共同的东西,而其他任务都可以看到。

我会添加更多代码,但代码插入只是一次占用一行而且不实用。

答案 1 :(得分:2)

您可以使用任务管理器的简单方法。例如:

public class TaskManager<T> {

private List<ForkJoinTask<T>> tasks;

public TaskManager() {
    tasks = new ArrayList<>();
}

public void addTask(ForkJoinTask<T> task) {
    tasks.add(task);
}

public void cancelAllExcludeTask(ForkJoinTask<Integer> cancelTask) {
    for (ForkJoinTask<T> task : tasks) {
        if (task != cancelTask) {
            task.cancel(true);
        }
    }
}

public void cancelTask(ForkJoinTask<Integer> cancelTask) {
    for (ForkJoinTask<T> task : tasks) {
        if (task == cancelTask) {
            task.cancel(true);
        }
    }
}

}

任务:

public class YourTask extends RecursiveTask<Integer> {

private TaskManager<Integer> taskManager;

@Override
protected Integer compute() {
        // stuff and fork
        newTask.fork();
        // do not forget to save in managers list
        taskManager.addTask(newTask);

        // another logic

        // if current task should be cancelled            
        taskManager.cancelTasks(this);

        // or if you have decided to cancel all other tasks
        taskManager.cancelAllExcludeTask(this);
}
}