что заставит одного исполнителя выполнить остановку обработки задач? - PullRequest
5 голосов
/ 05 декабря 2008

Я использую java.util.concurrent.ExecutorService, полученный при вызове Executors.newSingleThreadExecutor(). Этот ExecutorService может иногда останавливать обработку задач, даже если он не был выключен и продолжает принимать новые задачи без исключения. В конце концов, он создает достаточно очереди, чтобы мое приложение закрывалось с OutOfMemoryError исключениями.

Документация, по-видимому, указывает на то, что этот однопотоковый исполнитель должен пережить ошибки обработки задач, запустив новый рабочий поток, если необходимо заменить его, который умер Я что-то упустил?

Ответы [ 3 ]

10 голосов
/ 05 декабря 2008

Похоже, у вас есть две разные проблемы:

1) Вы перегружаете рабочую очередь. Вы не можете просто добавлять новые задачи в очередь, не обращая внимания на уровень потребления исполнителей задач. Вам нужно разобраться в логике, чтобы знать, когда нужно блокировать новые добавления в рабочей очереди.

2) Любое неперехваченное исключение в потоке задачи может полностью убить поток. Когда это происходит, ExecutorService запускает новый поток для его замены. Но это не значит, что вы можете игнорировать любую проблему, которая может привести к потере потока! Найдите эти необъяснимые исключения и поймайте их!

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

По крайней мере, таков мой опыт работы с пулами потоков и исполнителями задач.


Хорошо, вот еще одна возможность, которая звучит выполнимо на основе вашего комментария (что все будет работать гладко в течение нескольких часов, пока внезапно не остановится) *

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

Вот как я бы диагностировал эту проблему:

Устранить ВСЕ разделяемое состояние между потоками задач. Во-первых, для этого может потребоваться, чтобы каждый поток задач создавал защитную копию всех необходимых им общих структур данных. После того, как вы это сделаете, совершенно невозможно будет зайти в тупик.

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

Что касается меня, всякий раз, когда я пишу код, который обрабатывает параллельные задачи с пулами потоков и исполнителями, я всегда стараюсь исключить общее состояние ALL между этими задачами. Что касается приложения, они также могут быть полностью автономными приложениями. Выискивание взаимоблокировок - это перетаскивание, и, по моему опыту, лучший способ устранить взаимоблокировки состоит в том, чтобы каждый поток имел свое собственное локальное состояние, а не делил какое-либо состояние с другими потоками задач.

Удачи!

3 голосов
/ 05 декабря 2008

Я думаю, что ваши задачи блокируются на неопределенный срок, а не умирают. Есть ли у вас доказательства, например, выписка из журнала в конце вашей задачи, свидетельствующая об успешном завершении ваших задач?

Это может быть тупик или взаимодействие с каким-то внешним процессом, который блокирует.

1 голос
/ 05 декабря 2008

Несмотря на то, что вы не оставляете достаточно деталей, чтобы быть уверенным, первое, что я попробую, - это чтобы ваши задачи перехватили «Исключение» на верхнем уровне и записали сообщение.

Я знаю, что это кажется неправильным, но иногда (в зависимости от большого количества переменных) я работал над кодом, в котором вещи, происходящие в потоке, выдают исключение, и оно никогда не регистрируется или просто не показывает на консоли - но «исполняющий» код выходит из цикла верхнего уровня или любого другого кода, вызывающего выполнение вашей задачи.

Полагаю, я просто говорю, убедитесь, что ваши задачи не выдают исключение.

...