Java: SingleThreadScheduledExecutor & java.утиль.параллельный.RejectedExecutionException


У меня есть эта проблема, у меня есть

private ScheduledExecutorService executor =  
     Executors.newSingleThreadScheduledExecutor(); 

И задача, которая создается каждые 50 миллисекунд:

executor.scheduleAtFixedRate(myTask, 0, 50, TimeUnit.MILLISECONDS);

myTask Иногда требуется некоторое время для завершения (например, 2-3 секунды или около того), но newSingleThreadScheduledExecutor гарантирует, что следующая запланированная задача myTask будет ждать завершения текущей.

Однако время от времени я получаю эту ошибку:

Выполнить: java.util.concurrent.RejectedExecutionException

Что мне делать? СПАСИБО

3 7

3 ответа:

Рассмотрим, что делает исполнитель. Он выполняет одну задачу каждые 50 миллисекунд, в соответствии с вашими инструкциями. Если предположить, что выполнение этой задачи занимает менее 50 миллисекунд, то все в порядке. Тем не менее, время от времени это занимает 2-3 секунды, чтобы бежать. Когда это происходит, исполнитель все еще пытается выполнить каждые 50 миллисекунд, но поскольку у него есть только один поток, он не может и отклоняет те выполнения, которые запускаются, пока ваша длительная задача все еще продолжается. Эта причина исключение, которое вы видите.

У вас есть два варианта исправить это (предполагая, что вы хотите придерживаться одной нити):

  1. Используйте scheduleWithFixedDelay вместо scheduleAtFixedRate. Если вы внимательно прочтете javadoc, вы увидите, что scheduleWithFixedDelay будет ждать 50 миллисекунд между завершением одной задачи и началом следующей, поэтому он никогда не будет "перекрываться", даже если одна из них занимает много времени. В отличие от этого, scheduleAtFixedRate будет пытаться выполнить каждые 50 миллисекунд, независимо от того, как долго каждый из них принимает.

  2. Измените способ, которым исполнитель обрабатывает сбои при выполнении. По умолчанию регистрируется исключение, но вы можете указать ему игнорировать его, например. Взгляните на подклассы of java.util.concurrent.RejectedExecutionHandler, например DiscardPolicy, которые просто молча отбрасывают задачу, которая не может быть выполнена. Вы можете использовать их, непосредственно конструируя ScheduledThreadPoolExecutor и передавая обработчик конструктору, а не используя класс фабрики Executors.

Я подозреваю, что Вариант (1) - это то, что вы хотите.

Это исключение будет выдано, когда либо:

  1. вы отключили исполнителя
  2. превышены границы исполнителя для его рабочей очереди или максимальных потоков.

Я предполагаю, что происходит последнее. Когда вы выполняете свою задачу, и это занимает много времени, то последующие запланированные задачи не могут быть запущены, потому что в пуле недостаточно доступных потоков.

Либо:

  1. Использовать использовать больший размер пула или использовать cachedThreadPool
  2. Измените политику отклонения, чтобы, например, использовать ThreadPoolExecutor.CallerRunsPolicy
  3. создайте отдельный исполнитель для выполнения долгосрочных задач и запустите их из запланированной задачи. На самом деле вы можете сделать это с помощью того же экземпляра Executor при условии, что вы увеличите размер пула.

Смотрите также ThreadPoolExecutor javadoc

С Java 7 оба они будут ждать, пока первое выполнение будет готово, а затем начать следующее!

Проверка here:
http://download.java.net/jdk7/archive/b123/docs/api/java/util/concurrent/ScheduledThreadPoolExecutor.html

Или here:
http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ScheduledThreadPoolExecutor.html