Warum wird vom Laichen von Threads im Java EE-Container abgeraten?

120

Eines der ersten Dinge, die ich über die Java EE-Entwicklung gelernt habe, ist, dass ich keine eigenen Threads in einem Java EE-Container erzeugen sollte. Aber wenn ich darüber nachdenke, kenne ich den Grund nicht.

Können Sie klar erklären, warum davon abgeraten wird?

Ich bin sicher, dass die meisten Unternehmensanwendungen asynchrone Jobs wie Mail-Daemons, Leerlaufsitzungen, Bereinigungsjobs usw. benötigen.

Also, wenn man in der Tat keine Threads erzeugen sollte, wie kann man das bei Bedarf richtig machen?

LiorH
quelle
4
Asynchrone Aufgaben werden normalerweise mithilfe von JMS-Messaging und MDBs ausgeführt.
Ken Liu
5
Dieses Problem sollte bald der Vergangenheit angehören, sobald JSR 236 in den Containern implementiert ist.
Letmaik
5
Es wurde davon abgeraten, da alle zweiten Threads vom Container erstellt und verwaltet werden sollten, damit der Thread Zugriff auf die anderen Unternehmensressourcen hat. Mit Java EE7 gibt es eine standardmäßige und korrekte Methode zum Erstellen von Threads in einer Unternehmensumgebung. Durch die Verwendung von Concurrency Utils stellen Sie sicher, dass Ihr neuer Thread erstellt und vom Container verwaltet wird, und stellen sicher, dass alle EE-Dienste verfügbar sind. Beispiel hier
Chris Ritchie
Einige korrekte Möglichkeiten in der JSF / EJB-Perspektive finden Sie hier: stackoverflow.com/q/6149919
BalusC

Antworten:

84

Es wird davon abgeraten, da alle Ressourcen in der Umgebung vom Server verwaltet und möglicherweise überwacht werden sollen. Außerdem wird ein Großteil des Kontexts, in dem ein Thread verwendet wird, normalerweise an den Ausführungsthread selbst angehängt. Wenn Sie einfach einen eigenen Thread starten (was meiner Meinung nach einige Server nicht einmal zulassen), kann er nicht auf andere Ressourcen zugreifen. Dies bedeutet, dass Sie keinen InitialContext abrufen und keine JNDI-Lookups durchführen können, um auf andere Systemressourcen wie JMS-Verbindungsfactorys und Datenquellen zuzugreifen.

Es gibt Möglichkeiten, dies "richtig" zu machen, dies hängt jedoch von der verwendeten Plattform ab.

Der commonj WorkManager ist für WebSphere und WebLogic sowie andere üblich

Mehr Infos hier

Und hier

Auch etwas dupliziert dieses von heute Morgen

UPDATE: Bitte beachten Sie, dass sich diese Frage und Antwort auf den Zustand von Java EE im Jahr 2009 bezieht. Seitdem haben sich die Dinge verbessert!

Robin
quelle
1
Sie können keinen InitialContext abrufen und keine JNDI-Lookups durchführen, um auf andere Systemressourcen wie JMS-Verbindungsfabriken und Datenquellen zuzugreifen. Ich habe eine App, die dies umgeht, indem sie die Datenquelle beim Starten der Threads einfügt, aber ich muss diesen Ansatz möglicherweise überdenken ...
Johnston
6
Es gibt jetzt eine standardmäßige und korrekte Methode zum Erstellen von Threads mit der Java EE-Kern-API. Durch die Verwendung von Concurrency Utils stellen Sie sicher, dass Ihr neuer Thread erstellt und vom Container verwaltet wird, und stellen sicher, dass alle EE-Dienste verfügbar sind. Beispiele hier und hier
Chris Ritchie
@ ChrisRitchie danke für den Tipp. Wenn nur JBoss AS / IBM Java EE 7 unterstützen würde ... :-(
asgs
1
@asgs Wildfly 8 (neuer Name für JBoss AS) unterstützt Java EE 7. IBM nur Java EE 6 zertifiziert Zertifizierung
Chris Ritchie
34

Für EJBs wird nicht nur davon abgeraten, es ist ausdrücklich durch die Spezifikation verboten :

Eine Enterprise-Bean darf keine Primitive für die Thread-Synchronisierung verwenden, um die Ausführung mehrerer Instanzen zu synchronisieren.

und

Die Enterprise-Bean darf nicht versuchen, Threads zu verwalten. Die Enterprise-Bean darf nicht versuchen, einen Thread zu starten, zu stoppen, anzuhalten oder fortzusetzen oder die Priorität oder den Namen eines Threads zu ändern. Die Enterprise-Bean darf nicht versuchen, Thread-Gruppen zu verwalten.

Der Grund dafür ist, dass EJBs in einer verteilten Umgebung betrieben werden sollen. Ein EJB kann von einem Computer in einem Cluster auf einen anderen verschoben werden. Gewinde (und Steckdosen und andere eingeschränkte Einrichtungen) sind ein erhebliches Hindernis für diese Portabilität.

Dan Dyer
quelle
3
Java EE7 Concurrency Utils bieten eine korrekte Möglichkeit, Threads in einer Unternehmensumgebung zu erstellen. Beispiele hier und hier
Chris Ritchie
1
@Dan Können Sie mir erklären, warum ein Thread die Portabilität des Verschiebens eines EJB von einer Maschine in einem Custer zu einer anderen erheblich behindert?
Geek
13

Der Grund, warum Sie keine eigenen Threads erzeugen sollten, ist, dass diese nicht vom Container verwaltet werden. Der Container kümmert sich um viele Dinge, die sich ein unerfahrener Entwickler nur schwer vorstellen kann. Beispielsweise werden Dinge wie Thread-Pooling, Clustering und Absturzwiederherstellungen vom Container ausgeführt. Wenn Sie einen Thread starten, können Sie einige davon verlieren. Mit dem Container können Sie auch Ihre Anwendung neu starten, ohne die JVM zu beeinflussen, auf der sie ausgeführt wird. Wie wäre dies möglich, wenn Threads außerhalb der Kontrolle des Containers liegen?

Dies ist der Grund, warum ab J2EE 1.4 Timer-Dienste eingeführt wurden. Weitere Informationen finden Sie in diesem Artikel.

kgiannakakis
quelle
2
JSR 236 fügte Funktionen zur Unterstützung von Spawning-Threads in Java EE 7 und höher hinzu. Siehe diese Geschwisterantwort von Chris Ritchie .
Basil Bourque
8

Parallelitätsdienstprogramme für Java EE

Es gibt jetzt eine standardmäßige und korrekte Methode zum Erstellen von Threads mit der Java EE-Kern-API:

Durch die Verwendung von Concurrency Utils stellen Sie sicher, dass Ihr neuer Thread erstellt und vom Container verwaltet wird, und stellen sicher, dass alle EE-Dienste verfügbar sind.

Beispiele hier

Chris Ritchie
quelle
2

Sie können den Container jederzeit anweisen, Dinge als Teil Ihrer Bereitstellungsdeskriptoren zu starten. Diese können dann alle Wartungsaufgaben ausführen, die Sie ausführen müssen.

Beachte die Regeln. Du wirst eines Tages froh sein, dass du es getan hast :)

Thorbjørn Ravn Andersen
quelle
2

Threads sind in Java EE-Containern gemäß den Blaupausen verboten. Weitere Informationen finden Sie in den Bauplänen .

Ojitha
quelle
2

Es gibt keinen wirklichen Grund, dies nicht zu tun. Ich habe Quarz mit Spring ohne Probleme in einer Webanwendung verwendet. Es kann auch das Parallelitäts-Framework java.util.concurrentverwendet werden. Wenn Sie Ihre eigene Thread-Behandlung implementieren, setzen Sie die Theads auf deamon oder verwenden Sie eine eigene deamon-Thread-Gruppe, damit der Container Ihre Webanwendung jederzeit entladen kann.

Aber seien Sie vorsichtig, die Bean Scopes- Sitzung und -Anforderung funktionieren nicht in gespawnten Threads! Auch anderer Code, auf den gebündelt wird, ThreadLocalfunktioniert nicht sofort. Sie müssen die Werte selbst auf die erzeugten Threads übertragen.

Arne Burmeister
quelle
1

Ich habe nie gelesen, dass es entmutigt ist, außer der Tatsache, dass es nicht einfach ist, es richtig zu machen.

Es ist eine ziemlich einfache Programmierung, und wie bei anderen Techniken auf niedriger Ebene sollten Sie einen guten Grund haben. Die meisten Parallelitätsprobleme können mithilfe integrierter Konstrukte wie Thread-Pools weitaus effektiver gelöst werden.

Levand
quelle
7
es ist in der Tat durch die Spezifikation verboten.
Ken Liu
1

Ein Grund, den ich gefunden habe, wenn Sie einige Threads in Ihrem EJB erzeugen und dann versuchen, den Container zu entladen oder Ihren EJB zu aktualisieren, werden Sie auf Probleme stoßen. Es gibt fast immer eine andere Möglichkeit, etwas zu tun, bei dem Sie keinen Thread benötigen. Sagen Sie einfach NEIN.

Javamann
quelle