Kürzlich hatte ich die Gelegenheit einen sehr interessanten Vortrag von Adam Bien anzuhören, der unter anderem Future in einem Teil seiner Beispielanwendung benutzt hat. Future bietet einen sehr eleganten Ansatz um Aufgaben in Java parallel auszuführen. Warum es also nicht mal selber in einem kleinen Beispiel ausprobieren und bei der Gelegenheit das Ganze in einen kurzen Blogbeitrag verpacken. Also los geht’s.
Der beste Anfang ist hier erstmal unsere Beispielklasse:
Der hier implementierte Algorithmus (nicht sicher, ob ich es wirklich einen Algorithmus nennen sollte ;)) prüft für eine gegebene Menge von Zahlen, wie viele von diesen durch eine bestimmte Zahl teilbar sind. Dies soll wirklich nur als Beispiel für die Implementierungstechnik dienen, natürlich könnten wir auch berechnen warum 42 die Antwort auf die ultimative Frage des Lebens, der Universums uns allem Anderen ist . Für den Moment möchte ich persönlich aber doch eher bei den trivialen Problemen bleiben.
Die main-Methode wird nur gebraucht, um die beiden Varianten der Berechnung aufzurufen und damit die Zeit für die Ausführung zu berechnen. Die erste Methode amountOfDivisibleBy ist dabei wirklich trivial und braucht denke ich keine weitere Erläuterung. Bei der zweiten Methode amountOfDivisibleByFuture wird es interessant.
Zunächst brauchen wir hier einen Executor, der später benutzt wird um die Future-Tasks zu starten. Die Tasks werden zur späteren Verarbeitung in einer Liste abgelegt:
Um dieses Beispiel möglichst einfach zu halten werden die beiden Future-Instanzen hart-codiert erzeugt, zur Liste hinzugefügt und dann mit Hilf des Executors ausgeführt. Und jetzt kommt der Kniff an der ganzen Sache. Wir haben jetzt zwei Objekte, welche die Ausführung unseres Algorithmus übernehmen.
Für diese Objekte gibt es nun verschiedene Möglichkeiten zu prüfen, ob die Verarbeitung bereits fertig ist. In diesem Beispiel macht es Sinn in einer Schleife den „blockierenden Aufruf“ get auf unseren Future-Objekten auszuführen. ein solcher Aufruf kommt erst zurück, wenn die Bearbeitung abgeschlossen ist, d.h. der erste Aufruf wird vermutlich länger dauern und der zweite wird fast direkt ein Ergebnis zurückliefern, vorausgesetzt die Hardware ermöglicht eine schnelle parallel Verarbeitung. Die Ergebnisse der beiden Teilaufgaben werden dann nur noch addiert und zurück geliefert am Ende der Methode
Und tatsächlich kann man sehen, dass die Methode welche Future nutzt fast doppelt so schnell ist wie die rein sequentielle Verarbeitung.
Result : 666666667 calculated in 12500 ms
Result (Future): 666666667 calculated in 6922 ms
Wie so oft in dieser Art Blogbeitrag ist das Beispiel natürlich recht künstlich, aber hoffentlich wird trotzdem deutlich wie Future genutzt werden kann, um Tasks in Java parallel auszuführen. Und vielleicht wartet ja schon eine echte Aufgabe darauf mit Hilfe dieses Features gelöst zu werden.
Blog-Autor*in
Thomas Jaspers
Senior Software Engineer & AI Enthusiast
Du hast noch Fragen zu diesem Thema? Dann sprich mich einfach an.
Du hast noch Fragen zu diesem Thema? Dann sprich mich einfach an.