Kolumne EnterpriseTales

Java 8 und Java EE: Are we there yet?

Arne Limburg, Lars Röwekamp

©Shutterstock.com/Sergey Nivens

Im Rahmen dieser Kolumne haben wir anlässlich des Java-8-Releases eine kleine Serie gestartet, in der wir uns das Zusammenspiel von Java 8 mit Enterprise Java näher anschauen wollen. Während wir in der letzten Kolumne die Möglichkeit der Nutzung mit Servern und Frameworks betrachtet haben, wollen wir heute einen Blick auf das Zusammenspiel der Lambda Expressions und des Streaming API mit Enterprise Java werfen.

Java 8 Features in the Enterprise

In der letzten Kolumne haben wir betrachtet, was Java 8 im Enterprise-Kontext bedeutet. Dabei lag der Fokus darauf, ob Java 8 überhaupt mit Enterprise Java zusammen funktioniert und wo die Probleme liegen. Um das Fazit der letzten Kolumne kurz zusammenzufassen: Im Java-EE-Standard lässt sich Java 8 nur mit dem Wildfly-Server verwenden. Außerhalb des EE-Standards sieht die Welt aber besser aus: Die Web-Container Tomcat und Jetty laufen beide mit Java 8. Im Frameworkbereich ist die Lage durchwachsen, aber zumindest die aktuellen Versionen von Spring und Hibernate laufen mit Java 8. Es gilt also: Java 8 kann im Enterprise-Bereich noch nicht flächendeckend eingesetzt werden, es gibt aber bereits Enterprise-Umgebungen, in denen es läuft. Grund genug für uns zu betrachten, wie die neuen Features von Java 8 im Enterprise-Umfeld eingesetzt werden können.

Enterprise Java und Lambda Expressions

Unter Verwendung von Java 8 und Lambda Expressions ist es z. B. sehr elegant möglich, Collections zu bearbeiten. Das gilt natürlich auch im Java-EE-Umfeld. So wird die Abarbeitung einer Liste von Entitäten zum Einzeiler:

entityList.forEach((MyEntity entity) -> { entity.doWork(); }) 

Interessant wird eine solche Operation, wenn man sie asynchron ausführen möchte. Ein besonderes Augenmerk muss dabei auf die Fälle gelegt werden, bei denen auf den EntityManager zugegriffen werden muss. Um nämlich in einem anderen Thread einen EntityManager zur Verfügung zu haben, muss darauf geachtet werden, dass der verwendete Thread Container-managed ist. Das gilt auch für die Verwendung von EJBs und CDI Beans (jedenfalls deren Proxies). In einem Container-managed Thread stehen einem alle EE-Features wie Dependency Injection, Transaktionen oder Security zur Verfügung. Die Ausführung in einem Container-managed Thread erreicht man entweder durch den Aufruf einer EJB-Methode, die mit @Async annotiert ist oder über die Concurrency Utilities, die im Rahmen von Java EE 7 neu hinzugekommen sind (siehe JCP). Letztere funktionieren auch wunderbar mit Lambda Expressions (Listing 1).Die richtig großen Vorteile der Lambda Expressions kommen aber erst im Zusammenspiel mit dem Streaming API zum Tragen.

@Resource
private ManagedThreadPool pool;
@PersistenceContext
private EntityManager entityManager;

public void calculate() {
  pool.submit(() -> {
      final List<MyEntity> entities
        = entityManager.createQuery(MyEntity.FIND_ALL).getResultList();
      entities.forEach((MyEntity entity) -> entity.doWork());
  });
}

Java Streaming API und das Fork-Join-Framework

Zusätzlich zu einfachen Collection-Operationen, wie dem gerade vorgestellten forEach, ermöglicht das Streaming API in Kombination mit Lambda Expressions komplexe Operationen auf Collections und das recht übersichtlich. Auch das Streaming API funktioniert natürlich in Java EE und über die Concurrency Utilities asynchron. Das gilt allerdings nur mit einer Einschränkung. Das Streaming API hat eine Methode, mit der ausgeführte Operationen direkt parallel (also asynchron) ausgeführt werden können. Das geschieht, indem man im Stream die Methode parallel() aufruft. Da stellt sich natürlich sofort die Frage, ob die so erzielte Parallelität auch mit Java EE zusammenspielt, ob also in den verwendeten Threads die Java-EE-Features zur Verfügung stehen, was bei Container-managed Threads der Fall wäre. Die Antwort ist leider: Nein. Die Parallelität wird nämlich über das Fork-Join-Framework realisiert und in einem ForkJoinPool ausgeführt. Von diesem gibt es leider im Java-EE-Standard keine „managed“ Variante, weil es der ManagedExecutorService aus den Concurrency Utilities nicht von ForkJoinPool ableitet und es keine Container-managed Variante der ForkJoinWorkerThreadFactory gibt. Die ManagagedThreadFactory erzeugt leider keine ForkJoinWorkThreads. Hier bleibt nur zu hoffen, dass diese Lücke in der Spezifikation in Java EE 8 nachgeholt wird und dann ein Container-managed ForkJoinPool zur Verfügung steht. Davon ist aber stark auszugehen. Für den Wildfly gibt es jedenfalls schon den Vorschlag, einen solchen Container-managed Pool bereits jetzt, außerhalb des Standards zur Verfügung zu stellen. Idealerweise sollte dieser in Java EE dann auch der Default-Pool für die Ausführung der Methode parallel() sein. Bis dahin muss man die Methode in Java EE mit Vorsicht genießen und sich bewusst sein, dass man bei den dann ausgeführten Operationen keinen Java-EE-Kontext zur Verfügung hat.

Fazit

Sofern Java 8 mit dem verwendeten Server und Frameworks läuft, lassen sich natürlich auch die Java-8-Features wie Lambda Expressions und Streaming API in Java EE verwenden. Vorsicht ist geboten, wenn man sich in den Multi-Threading-Bereich begibt. Um EJBs, CDI Beans, EntityManager, Transaktionen und Co in weiteren Threads zur Verfügung zu haben, muss man auf die Concurrency Utilities for Java EE zurückgreifen. Diese unterstützen leider das Fork-Join-Framework noch nicht, sodass aktuell auf die Möglichkeit der parallelen Verarbeitung des Streaming API verzichtet werden muss. Dies ist ein Feature der Concurrency Utilities, das sicherlich in Java EE 8 kommen wird.

Aufmacherbild: Conceptual image of businessteam working cohesively. Interaction and unity von Shutterstock / Urheberrecht: Sergey Nivens

Geschrieben von
Arne Limburg
Arne Limburg
Arne Limburg ist Softwarearchitekt bei der open knowledge GmbH in Oldenburg. Er verfügt über langjährige Erfahrung als Entwickler, Architekt und Consultant im Java-Umfeld und ist auch seit der ersten Stunde im Android-Umfeld aktiv.
Lars Röwekamp
Lars Röwekamp
Lars Röwekamp ist Gründer des IT-Beratungs- und Entwicklungsunternehmens open knowledge GmbH, beschäftigt sich im Rahmen seiner Tätigkeit als „CIO New Technologies“ mit der eingehenden Analyse und Bewertung neuer Software- und Technologietrends. Ein besonderer Schwerpunkt seiner Arbeit liegt derzeit in den Bereichen Enterprise und Mobile Computing, wobei neben Design- und Architekturfragen insbesondere die Real-Life-Aspekte im Fokus seiner Betrachtung stehen. Lars Röwekamp, Autor mehrerer Fachartikel und -bücher, beschäftigt sich seit der Geburtsstunde von Java mit dieser Programmiersprache, wobei er einen Großteil seiner praktischen Erfahrungen im Rahmen großer internationaler Projekte sammeln konnte.
Kommentare

Hinterlasse einen Kommentar

Hinterlasse den ersten Kommentar!

avatar
400
  Subscribe  
Benachrichtige mich zu: