Несколько SingleThreadExecutors для данного приложения ... хорошая идея? - PullRequest
1 голос
/ 22 декабря 2009

Этот вопрос о последствиях использования SingleThreadExecutor (JDK 1.6). Ранее на этом форуме задавались похожие вопросы, но я считаю, что ситуация, с которой я сталкиваюсь, несколько иная.

Различные компоненты приложения (назовем компоненты C1, C2, C3 и т. Д.) Генерируют (исходящие) сообщения, в основном в ответ на сообщения (входящие), которые они получают от других компонентов. Эти исходящие сообщения хранятся в очередях, которые обычно составляют ArrayBlockingQueue экземпляра - возможно, довольно стандартная практика. Однако исходящие сообщения должны быть обработаны в порядке их добавления. Я думаю, что использование SingleThreadExector является очевидным ответом здесь. В итоге получается ситуация 1: 1 - one SingleThreadExecutor для one очереди (которая предназначена для сообщений, исходящих из one component).

Теперь количество компонентов (C1, C2, C3 ...) неизвестно в данный момент. Они появятся в зависимости от потребностей пользователей (и, в конечном итоге, будут также утилизированы). Речь идет о 200-300 таких компонентов при пиковой нагрузке. Следуя принципу 1: 1, указанному выше, мы планируем 200 SingleThreadExecutor с. Это источник моего запроса здесь.

Мне не нравится мысль о том, что мне нужно создать столько SingleThreadExecutor с. Я бы предпочел использовать пул SingleThreadExecutor s, если это имеет смысл и правдоподобно (какие-либо готовые, видимые до этого классы / шаблоны?) Я прочитал много постов о рекомендованном использовании SingleThreadExecutor здесь, но как насчет пула того же самого?

Что думают здесь ученые женщины и мужчины? Я хотел бы, чтобы меня направляли, исправляли или просто предупреждали: -).

Ответы [ 4 ]

1 голос
/ 22 декабря 2009

Если вы требуете, чтобы сообщения обрабатывались в том порядке, в котором они были опубликованы, то вам нужен один и только один SingleThreadExecutor. Если у вас несколько исполнителей, то сообщения будут обрабатываться не по порядку в наборе исполнителей.

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

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

0 голосов
/ 16 марта 2016

Невозможно сказать, будут ли 300 или даже 3000 потоков вызывать какие-либо проблемы, не зная больше о вашем приложении. Я настоятельно рекомендую вам профилировать ваше приложение, прежде чем добавлять больше сложности

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

Самый простой способ ограничить количество запущенных потоков - использовать семафор. Приобретите семафор перед началом работы и отпустите его после завершения работы.

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

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

Размещать работу в очереди просто: добавьте полезную нагрузку и личность производителя.

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

0 голосов
/ 22 декабря 2009

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

0 голосов
/ 22 декабря 2009

Обмен сообщениями и пакетные задания - это то, что решается снова и снова. Я предлагаю не пытаться решить это снова. Вместо этого загляните в Quartz, который поддерживает пулы потоков, постоянные задачи в базе данных и т. Д. Или, возможно, еще лучше загляните в JMS / ActiveMQ. Но, по крайней мере, посмотрите на Кварц, если вы еще этого не сделали. О, и Spring делает работу с Кварцем намного проще ...

...