{"id":3868,"date":"2017-06-15T22:51:16","date_gmt":"2017-06-15T20:51:16","guid":{"rendered":"http:\/\/www.tutego.de\/blog\/javainsel\/?p=3868"},"modified":"2020-05-29T19:22:23","modified_gmt":"2020-05-29T17:22:23","slug":"asnychrones-programmieren-mit-completablefuture-completionstage","status":"publish","type":"post","link":"https:\/\/www.tutego.de\/blog\/javainsel\/2017\/06\/asnychrones-programmieren-mit-completablefuture-completionstage\/","title":{"rendered":"Asynchrones Programmieren mit CompletableFuture (CompletionStage)"},"content":{"rendered":"<p>So sch\u00f6ne an Future-Objekten ist die Abarbeitung im Hintergrund und die M\u00f6glichkeit, sp\u00e4ter abzufragen, ob das Ergebnis schon da ist. Allerdings fehlt der Future-Schnittstelle eine Methode, automatisch nach der Fertigstellung einen Folgeauftrag abzuarbeiten. Daf\u00fcr bietet die Java-Bibliothek eine spezielle Unterklasse CompletableFuture. Die Klasse implementiert die Schnittstelle CompletionStage, die vermutlich die gr\u00f6\u00dfte Anzahl Operationen in der gesamten Java SE hat. Der Typname dr\u00fcckt aus, das es um die Fertigstellung (engl. completion) von Abschnitten (engl. stage) geht.<\/p>\n<p>Ein Beispiel f\u00fcr einen trinkfesten mutigen Piraten:<\/p>\n<pre>package com.tutego.insel.concurrent;\n\n\n\n\nimport java.time.LocalTime;\n\nimport java.util.concurrent.CompletableFuture;\n\nimport java.util.concurrent.TimeUnit;\n\nimport java.util.logging.Logger;\n\n\n\n\nclass Pirate {\n\n\n\n\n&nbsp; public static void main( String[] arg ) throws Throwable {\n\n\n\n\n&nbsp;&nbsp;&nbsp; String result = CompletableFuture.supplyAsync( Pirate::newName )\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .thenApply( Pirate::swears )\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .thenCombine( drinkRum(), Pirate::combinePiratAndDrinks )\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .thenCombine( drinkRum(), Pirate::combinePiratAndDrinks )\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .get();\n\n&nbsp;&nbsp;&nbsp; System.out.println( result ); \/\/ Pirat Guybrush flucht und trinkt dann 10 Flaschen Rum und trinkt dann 11 Flaschen Rum\n\n&nbsp; }\n\n\n\n\n&nbsp; static String newName() {\n\n&nbsp;&nbsp;&nbsp; Logger.getGlobal().info( \"\" + Thread.currentThread() );\n\n&nbsp;&nbsp;&nbsp; return \"Pirat Guybrush\";\n\n&nbsp; }\n\n\n\n\n&nbsp; static String swears( String pirate ) {\n\n&nbsp;&nbsp;&nbsp; Logger.getGlobal().info( \"\" + Thread.currentThread() );\n\n&nbsp;&nbsp;&nbsp; return pirate + \" flucht\";\n\n&nbsp; }\n\n\n\n\n&nbsp; static CompletableFuture&lt;Integer&gt; drinkRum() {\n\n&nbsp;&nbsp;&nbsp; Logger.getGlobal().info( \"\" + Thread.currentThread() );\n\n&nbsp;&nbsp;&nbsp; try { TimeUnit.SECONDS.sleep( 1 ); } catch ( Exception e ) { }\n\n&nbsp;&nbsp;&nbsp; return CompletableFuture.supplyAsync( () -&gt; LocalTime.now().getSecond() );\n\n&nbsp; }\n\n\n\n\n&nbsp; static String combinePiratAndDrinks( String pirat, int bottlesOfRum ) {\n\n&nbsp;&nbsp;&nbsp; Logger.getGlobal().info( \"\" + Thread.currentThread() );\n\n&nbsp;&nbsp;&nbsp; return pirat + \" und trinkt dann \" + bottlesOfRum + \" Flaschen Rum\";\n\n&nbsp; }\n\n}<\/pre>\n<p>Die Ausgabe ist:<\/p>\n<pre>Juni 15, 2017 10:41:56 NACHM. com.tutego.insel.thread.concurrent.Pirate drinkRum\n\nINFORMATION: Thread[main,5,main]\n\nJuni 15, 2017 10:41:56 NACHM. com.tutego.insel.thread.concurrent.Pirate newName\n\nINFORMATION: Thread[ForkJoinPool.commonPool-worker-1,5,main]\n\nJuni 15, 2017 10:41:56 NACHM. com.tutego.insel.thread.concurrent.Pirate swears\n\nINFORMATION: Thread[ForkJoinPool.commonPool-worker-1,5,main]\n\nJuni 15, 2017 10:41:57 NACHM. com.tutego.insel.thread.concurrent.Pirate combinePiratAndDrinks\n\nINFORMATION: Thread[main,5,main]\n\nJuni 15, 2017 10:41:57 NACHM. com.tutego.insel.thread.concurrent.Pirate drinkRum\n\nINFORMATION: Thread[main,5,main]\n\nJuni 15, 2017 10:41:58 NACHM. com.tutego.insel.thread.concurrent.Pirate combinePiratAndDrinks\n\nINFORMATION: Thread[main,5,main]\n\nPirat Guybrush flucht und trinkt dann 57 Flaschen Rum und trinkt dann 58 Flaschen Rum<\/pre>\n<p>Zum Programm: Zun\u00e4chst muss die Kette von Abschnitten aufgebaut werden. Das kann entweder mit dem Standardkonstruktor geschehen, oder mit statischen Methoden. In unserem Fall nutzen wir supplyAsync(Supplier&lt;U&gt; supplier). Die Methode nimmt sich einen freien Thread aus dem ForkJoinPool.commonPool() und l\u00e4sst den Thread den supplier abarbeiten. Das Ergebnis ist \u00fcber die R\u00fcckgabe, einem CompletableFuture, abrufbar. Als n\u00e4chsten wenden wir thenApply(Function&lt;? super T,? extends U&gt; fn) an, die vergleichbar ist mit einer map(\u2026)-Operation eines Streams. Interessant wird es bei thenCombine(CompletionStage&lt;? extends U&gt; other, BiFunction&lt;? super T,? super U,? extends V&gt; fn); sie verbindet das Ergebnis der eigenen CompletionStage \u00fcber eine Funktion mit einer anderen CompletionStage, die wir in unserem Fall auch wieder mit supplyAsync(\u2026) aufbauen. So kombinieren wir zwei unabh\u00e4ngige CompletionStage miteinander und synchronisieren das Ergebnis. Wir k\u00f6nnen das gut an der Ausgabe auslesen, dass drinkRum ganz am Anfang schon ausgef\u00fchrt wird, und zwar vom Thread[main,5,main], nicht vom ForkJoinPool, weil es unabh\u00e4ngig von den anderen l\u00e4uft.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>So sch\u00f6ne an Future-Objekten ist die Abarbeitung im Hintergrund und die M\u00f6glichkeit, sp\u00e4ter abzufragen, ob das Ergebnis schon da ist. Allerdings fehlt der Future-Schnittstelle eine Methode, automatisch nach der Fertigstellung einen Folgeauftrag abzuarbeiten. Daf\u00fcr bietet die Java-Bibliothek eine spezielle Unterklasse CompletableFuture. Die Klasse implementiert die Schnittstelle CompletionStage, die vermutlich die gr\u00f6\u00dfte Anzahl Operationen in der [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":"","_links_to":"","_links_to_target":""},"categories":[1,11,85],"tags":[],"class_list":["post-3868","post","type-post","status-publish","format-standard","hentry","category-allgemein","category-insel","category-java-9"],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/posts\/3868","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/comments?post=3868"}],"version-history":[{"count":4,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/posts\/3868\/revisions"}],"predecessor-version":[{"id":4498,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/posts\/3868\/revisions\/4498"}],"wp:attachment":[{"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/media?parent=3868"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/categories?post=3868"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/tags?post=3868"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}