Java: SingleThreadScheduledExecutor & java.util.concurrent.RejectedExecutionException - PullRequest
8 голосов
/ 21 декабря 2009

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

private ScheduledExecutorService executor =  
     Executors.newSingleThreadScheduledExecutor(); 

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

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

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

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

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

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

Ответы [ 3 ]

13 голосов
/ 21 декабря 2009

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

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

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

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

Я подозреваю, что вам нужен вариант (1).

4 голосов
/ 21 декабря 2009

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

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

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

Или:

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

См. Также ThreadPoolExecutor javadoc

0 голосов
/ 05 июня 2014

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

проверьте здесь:
http://download.java.net/jdk7/archive/b123/docs/api/java/util/concurrent/ScheduledThreadPoolExecutor.html

или здесь:
http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ScheduledThreadPoolExecutor.html

...