Исполнители Java:как я могу остановить отправленные задачи?

StackOverflow https://stackoverflow.com/questions/1418033

Вопрос

Я отправил задачу с использованием исполнителей, и мне нужно, чтобы она остановилась через некоторое время (например,5 минут).Я пробовал сделать так:

   for (Future<?> fut : e.invokeAll(tasks, 300, TimeUnit.SECONDS)) {
         try {
             fut.get(); 
         } catch (CancellationException ex) {
             fut.cancel(true);   
             tasks.clear();
         } catch(ExecutionException ex){
             ex.printStackTrace(); //FIXME: gestita con printstack       
         }
   }

Но я всегда получаю сообщение об ошибке:У меня есть общий вектор, который необходимо изменить задачами, а затем прочитать потоком, и даже если я остановлю всю задачу, если произойдет тайм-аут, я получу:

Exception in thread "Thread-1" java.util.ConcurrentModificationException

Здесь что-то не так?Как я могу остановить отправленные задачи, которые все еще работают через 5 минут?

Это было полезно?

Решение

Просто потому, что ты звонишь cancel() на Future не означает, что задача остановится автоматически.Вам нужно проделать некоторую работу внутри задачи, чтобы убедиться, что она остановится:

  • Использовать cancel(true) чтобы на задачу было отправлено прерывание.
  • Ручка InterruptedException.Если функция в вашей задаче выдает InterruptedException, убедитесь, что вы завершили работу корректно как можно скорее после обнаружения исключения.
  • Периодически проверяйте Thread.currentThread().isInterrupted() если задача выполняет непрерывные вычисления.

Например:

class LongTask implements Callable<Double> {
    public Double call() {

         // Sleep for a while; handle InterruptedException appropriately
         try {
             Thread.sleep(10000);
         } catch (InterruptedException ex) {
             System.out.println("Exiting gracefully!");
             return null;
         }


         // Compute for a while; check Thread.isInterrupted() periodically
         double sum = 0.0;
         for (long i = 0; i < 10000000; i++) {
             sum += 10.0
             if (Thread.currentThread().isInterrupted()) {
                 System.out.println("Exiting gracefully");
                 return null;
             }
         }

         return sum;
    } 
}

Кроме того, как упоминалось в других сообщениях: ConcurrentModificationException может быть выброшено, даже если используется потокобезопасный Vector класс, потому что итераторы, которые вы получаете от Vector не являются потокобезопасными и поэтому должны быть синхронизированы.Расширенный цикл for использует итераторы, поэтому будьте осторожны:

final Vector<Double> vector = new Vector<Double>();
vector.add(1.0);
vector.add(2.0);

// Not thread safe!  If another thread modifies "vector" during the loop, then
// a ConcurrentModificationException will be thrown.
for (Double num : vector) {
    System.out.println(num);
}

// You can try this as a quick fix, but it might not be what you want:
synchronized (vector) {    // "vector" must be final
    for (Double num : vector) {
        System.out.println(num);
    }
}

Другие советы

ConcurrentModificationException поступает из вашего вызова tasks.clear () , пока ваши эксперты работают с вашими tasks Vector . То, что вы можете попытаться сделать, это вызвать shutdownNow () в вашем ExecutorService

Наиболее распространенный случай для ConcurrentModificationException - это когда vector изменяется одновременно с итерацией. Часто это будет сделано в один поток. Вам нужно удерживать блокировку на Vector на протяжении всей итерации (и избегать взаимоблокировки).

fut.get () является блокирующим вызовом, даже после истечения времени ожидания вы будете блокировать, пока задача не будет выполнена. Если вы хотите остановиться как можно ближе к 5-минутной отметке, вам нужно проверить флаг прерывания, я просто рекомендую вам сделать это с помощью метода Thread.isInterrupted (), который сохраняет состояние прерывания. Если вы хотите просто немедленно прекратить работу и не нужно очищать какое-либо состояние, генерируйте исключение, которое будет перехвачено Future и указано вам как ExecutionException.

fut.cancel (true) ничего не делает, так как метод invokeAll () уже сделал это для вас.

Если вы не используете " задачи " Сбор в другом месте, вам, вероятно, не нужно вызывать clear () для него. Это не будет источником вашей проблемы, так как метод invokeAll () выполняется со списком к тому времени, когда вы вызываете clear (). Но если вам нужно начать формировать список новых задач для выполнения, я предлагаю вам сформировать новый список задач, а не использовать старый список новых задач.

К сожалению, у меня нет ответа на вашу проблему. Я не вижу достаточно информации здесь, чтобы диагностировать это. Ничто в предоставленном вами фрагменте кода не указывает на неправильное (только ненужное) использование библиотечных классов / методов. Возможно, если вы включили полную трассировку стека вместо ошибки в одну строку.

Поместите fut.cancel (true); в блок finally

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top