Java: SingleThreadScheduledExecutor и java.util.concurrent. RejectedExecutionException

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

private ScheduledExecutorService executor =  
     Executors.newSingleThreadScheduledExecutor(); 

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

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

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

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

выполнитесь: java.util.concurrent.RejectedExecutionException

Что мне делать? Спасибо

8
задан astro8891 7 September 2017 в 03:02
поделиться

2 ответа

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

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

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

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

13
ответ дан 5 December 2019 в 10:41
поделиться

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

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

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

Либо:

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

См. Также ThreadPoolExecutor javadoc

4
ответ дан 5 December 2019 в 10:41
поделиться