Почему не рекомендуется создавать потоки в контейнере Java EE?

120

Одна из первых вещей, которые я узнал о разработке Java EE, - это то, что я не должен создавать свои собственные потоки внутри контейнера Java EE. Но когда я думаю об этом, я не знаю причины.

Можете ли вы четко объяснить, почему это не рекомендуется?

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

Итак, если действительно не следует создавать потоки, как правильно это делать при необходимости?

LiorH
источник
4
Асинхронные задачи обычно выполняются с использованием сообщений JMS и MDB.
Кен Лю
5
Эта проблема должна скоро уйти в прошлое, когда JSR 236 будет реализован в контейнерах.
letmaik
5
Это не приветствовалось, потому что любые вторые потоки должны создаваться и управляться контейнером, чтобы поток имел доступ к другим корпоративным ресурсам. В Java EE7 есть стандартный и правильный способ создания потоков в корпоративной среде. Используя Concurrency Utils, вы гарантируете, что ваш новый поток будет создан и управляется контейнером, что гарантирует доступность всех EE-сервисов. Пример здесь
Крис Ричи
Несколько правильных способов с точки зрения JSF / EJB можно найти здесь: stackoverflow.com/q/6149919
BalusC

Ответы:

84

Это не рекомендуется, потому что все ресурсы в среде предназначены для управления и, возможно, наблюдения за сервером. Кроме того, большая часть контекста, в котором используется поток, обычно прикрепляется к самому потоку выполнения. Если вы просто запустите свой собственный поток (который, я считаю, некоторые серверы даже не разрешат), он не сможет получить доступ к другим ресурсам. Это означает, что вы не можете получить InitialContext и выполнять поиск JNDI для доступа к другим системным ресурсам, таким как фабрики соединений JMS и источники данных.

Есть способы сделать это «правильно», но это зависит от используемой платформы.

Commonj WorkManager является общим для WebSphere и WebLogic, а также для других

Больше информации здесь

И тут

Также несколько дублирует это с сегодняшнего утра

ОБНОВЛЕНИЕ: обратите внимание, что этот вопрос и ответ относятся к состоянию Java EE в 2009 году, с тех пор ситуация улучшилась!

Робин
источник
1
вы не можете получить InitialContext и выполнять поиск JNDI для доступа к другим системным ресурсам, таким как фабрики соединений JMS и источники данных. У меня есть приложение, которое
помогает обойти это, внедряя
6
Теперь существует стандартный и правильный способ создания потоков с помощью основного API Java EE. Используя Concurrency Utils, вы гарантируете, что ваш новый поток будет создан и управляется контейнером, что гарантирует доступность всех EE-сервисов. Примеры здесь и здесь
Крис Ричи
@ChrisRitchie, спасибо за подсказку. если бы только JBoss AS / IBM WAS поддерживал Java EE 7 ... :-(
asgs
1
@asgs WildFly 8 (новое название JBoss AS) поддерживает Java EE 7. IBM имеет только сертифицированный сертификат
Крис Ричи
34

Для EJB это не только не рекомендуется, но и прямо запрещено спецификацией :

Корпоративный компонент не должен использовать примитивы синхронизации потоков для синхронизации выполнения нескольких экземпляров.

и

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

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

Дэн Дайер
источник
3
Утилиты Java EE7 Concurrency Utils обеспечивают правильный способ создания потоков в корпоративной среде. Примеры здесь и здесь
Крис Ричи
1
@Dan Можете ли вы объяснить мне, почему поток может стать серьезным препятствием для переносимости перемещения EJB с одной машины в кластере на другую?
Geek
13

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

Это причина того, что из J2EE 1.4 были введены службы таймера. Подробнее см. В этой статье.

kgiannakakis
источник
2
JSR 236 добавил функции для поддержки создания потоков в Java EE 7 и более поздних версиях. См. Ответ Криса Ричи .
Basil Bourque
8

Утилиты параллелизма для Java EE

Теперь существует стандартный и правильный способ создания потоков с помощью основного API Java EE:

Используя Concurrency Utils, вы гарантируете, что ваш новый поток будет создан и управляется контейнером, что гарантирует доступность всех EE-сервисов.

Примеры здесь

Крис Ричи
источник
2

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

Следовать правилам. Вы будете рады когда-нибудь, что сделали :)

Торбьёрн Равн Андерсен
источник
2

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

Ojitha
источник
2

Нет реальной причины не делать этого. Я без проблем использовал Quarz с Spring в веб-приложении. Также java.util.concurrentможет использоваться структура параллелизма . Если вы реализуете собственную обработку потоков, установите для theads значение deamon или используйте для них собственную группу потоков deamon, чтобы контейнер мог выгрузить ваше веб-приложение в любое время.

Но будьте осторожны, сеанс и запрос областей действия bean-компонентов не работают в порожденных потоках! Также другой код ThreadLocalне работает из коробки, вам нужно передать значения порожденным потокам самостоятельно.

Арне Бурмейстер
источник
1

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

Это довольно низкоуровневое программирование, и, как и другие низкоуровневые техники, у вас должна быть веская причина. Большинство проблем параллелизма можно решить гораздо эффективнее, используя встроенные конструкции, такие как пулы потоков.

Леванд
источник
7
это действительно запрещено спецификацией.
Кен Лю
1

Я обнаружил одну причину: если вы создаете несколько потоков в своем EJB, а затем пытаетесь выгрузить контейнер или обновить свой EJB, вы столкнетесь с проблемами. Почти всегда есть другой способ сделать что-то, где вам не нужен поток, поэтому просто скажите НЕТ.

Javamann
источник