Платформа не может отменить задачу по той же причине, по которой вы не можете отменить поток. См. документацию по Thread.stop() по всем причинам. Какие замки может держать задача? С какими внешними ресурсами он может быть связан? Все те же причины Thread.stop() применимы и к задачам (в конце концов, задачи выполняются в потоках). Вам нужно приказать задаче остановиться так же, как вы приказываете остановить поток.
Я управляю другим проектом fork/join, в котором используется метод разброса-сбора. Способ, которым я выполняю отмену или короткое замыкание, заключается в том, что каждой создаваемой задаче передается объект (PassObject), который имеет
protected volatile boolean stop_now = false;
и способ остановки задачи
protected void stopNow() {stop_now = true; }
Каждая задача периодически проверяет stop_now, и когда она принимает значение true, она изящно завершает задачу.
К сожалению, stop_now должен быть изменчивым, так как его будет устанавливать другой поток. Это может привести к значительным накладным расходам, если вы будете часто проверять его.
Как установить это поле в другой задаче, становится немного сложнее. Каждая задача, которую я создаю, также содержит ссылку на массив ссылок на каждую другую задачу.
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. С рекурсией вы не знаете, сколько уровней задач вам понадобится в начале. Опять же, вам нужно будет периодически проверять логическое значение true в своем коде и, когда оно истинно, корректно завершать задачу.
Вышеупомянутое является лишь намеком на то, как вы можете сделать отмену. Каждое приложение отличается. То, что я делаю, работает для моего приложения, но логика та же. Вам нужно что-то общее в каждой задаче, которую может ставить задача и которую могут видеть все остальные задачи.
Я бы добавил больше кода, но вставка кода занимает только одну строку за раз, и это нецелесообразно.
person
edharned
schedule
31.05.2014