תכנות אסינכרוני בג'אווה

1. סקירה כללית

עם הדרישה הגוברת לכתיבת קוד שאינו חוסם, אנו זקוקים לדרכים לבצע את הקוד בצורה סינכרונית.

במדריך זה נבחן כמה דרכים להשגת תכנות אסינכרוני ב- Java. כמו כן, נחקור כמה ספריות Java המספקות פתרונות מהקופסה.

2. תכנות אסינכרוני בג'אווה

2.1. פְּתִיל

אנו יכולים ליצור שרשור חדש לביצוע כל פעולה בצורה סינכרונית. עם שחרורם של ביטויים למבדה ב- Java 8, הוא נקי וקריא יותר.

בואו ניצור שרשור חדש המחשב ומדפיס את הפקטוריון של מספר:

מספר int = 20; שרשור newThread = חדש אשכול (() -> {System.out.println ("גורם של" + מספר + "הוא:" + עובדה (מספר));}); newThread.start ();

2.2. FutureTask

מאז Java 5, ה- עתיד ממשק מספק דרך לבצע פעולות אסינכרוניות באמצעות FutureTask.

אנחנו יכולים להשתמש ב- שלח שיטת ה- שירות ExecutorService כדי לבצע את המשימה בצורה סינכרונית ולהחזיר את המופע של ה- FutureTask.

אז בואו נמצא את הפקטוריון של מספר:

ExecutorService threadpool = Executors.newCachedThreadPool (); FutureTask Future = threadpool.submit (() -> עובדתי (מספר)); בעוד (! futureTask.isDone ()) {System.out.println ("FutureTask עדיין לא הסתיים ..."); } תוצאה ארוכה = futureTask.get (); threadpool.shutdown ();

הנה, השתמשנו ב- נעשה השיטה המסופקת על ידי עתיד ממשק כדי לבדוק אם המשימה הושלמה. לאחר סיום נוכל לאחזר את התוצאה באמצעות ה- לקבל שיטה.

2.3. העתיד

ג'אווה 8 הוצגה העתיד עם שילוב של א עתיד ו שלב השלמה. הוא מספק שיטות שונות כמו supplyAsync, runAsync, ו ואז החל Async לתכנות אסינכרוני.

אז בואו נשתמש ב- העתיד במקום ה FutureTask למצוא את הפקטוריון של מספר:

CompletableFuture completeableFuture = CompletableFuture.supplyAsync (() -> עובדתי (מספר)); בעוד (! completeableFuture.isDone ()) {System.out.println ("CompletableFuture עדיין לא הסתיים ..."); } תוצאה ארוכה = completeableFuture.get ();

אנחנו לא צריכים להשתמש ב- שירות ExecutorService בִּמְפוּרָשׁ. ה העתיד שימוש פנימי ForkJoinPool לטפל במשימה בצורה אסינכרונית. לפיכך, זה הופך את הקוד שלנו להרבה יותר נקי.

3. גויאבה

גויאבה מספק את האזנה לעתיד בכיתה לביצוע פעולות אסינכרוניות.

ראשית, נוסיף את האחרונה גויאבה תלות במייבון:

 com.google.guava גויאבה 28.2-jre 

לאחר מכן, בואו נמצא את הפקטוריון של מספר באמצעות ה- האזנה לעתיד:

ExecutorService threadpool = Executors.newCachedThreadPool (); שירות ListeningExecutorService = MoreExecutors.listeningDecorator (threadpool); ListenableFuture guavaFuture = (ListenableFuture) service.submit (() -> עובדתי (מספר)); תוצאה ארוכה = guavaFuture.get ();

הנה ה עוד מוציאים לפועל המחלקה מספקת את המופע של ListeningExecutorService מעמד. אז ה ListeningExecutorService.submit השיטה מבצעת את המשימה בצורה אסינכרונית ומחזירה את המופע של ה- האזנה לעתיד.

לגויאבה יש גם עתיד כיתה המספקת שיטות כמו submitAsync, לוח זמנים אסינכרון, ו transformAsync לשרשר את FutureFutures דומה ל העתיד.

לדוגמה, בואו נראה כיצד להשתמש Futures.submitAsync במקום ה ListeningExecutorService.submit שיטה:

שירות ListeningExecutorService = MoreExecutors.listeningDecorator (threadpool); AsyncCallable asyncCallable = Callables.asAsyncCallable (חדש ניתן להתקשרות () {ציבורי שיחה ארוכה () {החזר עובד (מספר);}}, שירות); ListenableFuture guavaFuture = Futures.submitAsync (asyncCallable, שירות);

הנה ה submitAsync השיטה דורשת ויכוח של AsyncCallable, שנוצר באמצעות ה- ניתנים להתקשרות מעמד.

בנוסף, ה- עתיד הכיתה מספקת את addCallback שיטה לרישום התקשרות חוזרת של הצלחה וכישלון:

Futures.addCallback (factorialFuture, FutureCallback חדש () {public void onSuccess (Long factorial) {System.out.println (factorial);} public public onFailure (Throwable throw) {throw.getCause ();}}, service);

4. EA אסינק

האומנות האלקטרונית הביאה את התכונה המיוחלת ל- async מ- .NET למערכת האקולוגית של Java דרך ה- ea-async סִפְרִיָה.

הספרייה מאפשרת לכתוב קוד אסינכרוני (שאינו חוסם) ברצף. לכן זה הופך את התכנות האסינכרוני לקל יותר ומשתנה באופן טבעי.

ראשית, נוסיף את האחרונה ea-async תלות במייבון pom.xml:

 com.ea.async ea-async 1.2.3 

לאחר מכן, בואו נהפוך את הדברים שנדונו בעבר העתיד קוד באמצעות לְהַמתִין השיטה המסופקת על ידי EA אסינכרון מעמד:

סטטי {Async.init (); } factorialUsingEAAsync ציבורי ארוך (int מספר) {CompletableFuture completeableFuture = CompletableFuture.supplyAsync (() -> factorial (number)); תוצאה ארוכה = Async.await (completeFuture); }

הנה, אנו מתקשרים אל ה- Async.init שיטה ב סטָטִי לחסום כדי לאתחל את אסינכרון מכשור לזמן ריצה.

אסינכרון מכשור הופך את הקוד בזמן ריצה ומשכתב את השיחה ל לְהַמתִין שיטה, להתנהג באופן דומה לשימוש בשרשרת של העתיד.

לָכֵן, השיחה אל לְהַמתִין שיטה דומה להתקשרות עתיד. הצטרף.

אנחנו יכולים להשתמש ב - javaagent פרמטר JVM למכשור זמן הידור. זו אלטרנטיבה ל Async.init שיטה:

java -javaagent: ea-async-1.2.3.jar -cp 

בואו נבחן דוגמה נוספת לכתיבת קוד אסינכרוני ברצף.

ראשית, נבצע כמה פעולות שרשרת באופן אסינכרוני בשיטות ההרכב כמו ואז ComposeAsync ו thenAcceptAsync של ה העתיד מעמד:

CompletableFuture completeableFuture = שלום () .thenComposeAsync (שלום -> mergeWorld (שלום)) .thenAcceptAsync (helloWorld -> הדפס (helloWorld)). באופן יוצא מן הכלל (זורק -> {System.out.println (throwable.getCause ()); להחזיר null ;}); completeableFuture.get ();

לאחר מכן נוכל לשנות את הקוד באמצעות EA Async.await ():

נסה {מחרוזת שלום = חכה (שלום ()); מחרוזת helloWorld = לחכות (mergeWorld (שלום)); לחכות (CompletableFuture.runAsync (() -> הדפס (helloWorld))); } לתפוס (חריג e) {e.printStackTrace (); }

היישום דומה לקוד החסימה הרציף. אולם, ה לְהַמתִין השיטה אינה חוסמת את הקוד.

כפי שנדון, כל השיחות אל לְהַמתִין השיטה תכתב מחדש על ידי אסינכרון מכשור לעבוד באופן דומה ל עתיד. הצטרף שיטה.

אז ברגע שהביצוע האסינכרוני של ה- שלום השיטה הסתיימה, עתיד התוצאה מועברת ל mergeWorld שיטה. לאחר מכן, התוצאה מועברת לביצוע האחרון באמצעות ה- CompletableFuture.runAsync שיטה.

5. קקטו

Cactoos היא ספריית Java המבוססת על עקרונות מונחים עצמים.

זוהי אלטרנטיבה ל- Google Guava ו- Apache Commons המספקת אובייקטים נפוצים לביצוע פעולות שונות.

ראשית, בואו נוסיף את האחרונה קקטוסים תלות במייבון:

 org.cactoos קקטו 0.43 

הספרייה מספקת אסינכרון מחלקה לפעולות אסינכרוניות.

אז אנחנו יכולים למצוא את הפקטוריון של מספר באמצעות המופע של Cactoos אסינכרון מעמד:

Async asyncFunction = Async חדש (קלט -> עובדה (קלט)); עתיד asyncFuture = asyncFunction.apply (מספר); תוצאה ארוכה = asyncFuture.get ();

פה, ה להגיש מועמדות השיטה מבצעת את הפעולה באמצעות ExecutorService.send שיטה ומחזירה מופע של עתיד מִמְשָׁק.

באופן דומה, ה אסינכרון בכיתה יש את ביצוע שיטה המספקת את אותה תכונה ללא ערך החזר.

הערה: ספריית Cactoos נמצאת בשלבי פיתוח ראשוניים וייתכן שעדיין אינה מתאימה לשימוש בייצור.

6. ג'קבי-היבטים

Jcabi-Aspects מספק את @ Async ביאור לתכנות אסינכרוני באמצעות היבטים של AspectJ AOP.

ראשית, בואו נוסיף את האחרונה היבטים של jcabi תלות במייבון:

 com.jcabi jcabi-aspect 0.22.6 

ה היבטים של jcabi הספרייה דורשת תמיכה של זמן ריצה של AspectJ. אז נוסיף את aspectjrt תלות במייבון:

 org.aspectj aspectjrt 1.9.5 

לאחר מכן נוסיף את תוסף jcabi-maven תוסף השוזר את הבינאריות עם היבטים של AspectJ. התוסף מספק את ajc מטרה שעושה את כל העבודה בשבילנו:

 com.jcabi jcabi-maven-plugin 0.14.1 ajc org.aspectj aspectjtools 1.9.1 org.aspectj aspectjweaver 1.9.1 

אז כולנו אמורים להשתמש בהיבטי AOP לתכנות אסינכרוני:

@Async @ ציבור ציבורי עתיד factorialUsingAspect (מספר int) {עתיד factorialFuture = CompletableFuture.completedFuture (גורם (מספר)); חזרה factorialFuture; }

כאשר אנו מרכיבים את הקוד, הספרייה תזריק ייעוץ של AOP במקום ה- @ Async ביאור באמצעות אריגת AspectJ, לביצוע אסינכרוני של ה- factorialUsingAspect שיטה.

אז בואו נערך את הכיתה באמצעות הפקודה Maven:

להתקין mvn

התפוקה מה- תוסף jcabi-maven עשוי להיראות כמו:

 --- jcabi-maven-plugin: 0.14.1: ajc (ברירת מחדל) @ java-async --- [INFO] jcabi-aspect 0.18 / 55a5c13 התחיל חוט דמון חדש jcabi-loggable לצפייה בשיטות המסומנות @Loggable [INFO] שיעורים לא ארוגים יועתקו אל / tutorials / java-async / target / unwoven [INFO] jcabi-aspect 0.18 / 55a5c13 התחיל חוט דמון חדש jcabi-cacheable לניקוי אוטומטי של ערכי @Cacheable שפג תוקף [INFO] תוצאת ajc: 10 קבצים ) מעובד, 0 קיצורי דרך ארוגים, 0 שגיאות, 0 אזהרות

אנו יכולים לאמת אם הכיתה שלנו שזורה כראוי על ידי בדיקת יומני ה- jcabi-ajc.log קובץ, שנוצר על ידי התוסף Maven:

הצטרפות לנקודה 'ביצוע שיטה (java.util.concurrent.Future com.baeldung.async.JavaAsync.factorialUsingJcabiAspect (int))' בסוג 'com.baeldung.async.JavaAsync' (JavaAsync.java:158) מומלץ על ידי עצות סביב מתוך 'com.jcabi.aspects.aj.MethodAsyncRunner' (jcabi-aspect-0.22.6.jar! MethodAsyncRunner.class (מתוך MethodAsyncRunner.java))

לאחר מכן, נפעיל את הכיתה כיישום Java פשוט, והפלט ייראה כך:

17: 46: 58.245 [main] INFO com.jcabi.aspects.aj.NamedThreads - jcabi-aspect 0.22.6 / 3f0a1f7 התחיל חוט דמון חדש jcabi-loggable לצפייה בשיטות המסומנות @Loggable 17: 46: 58.355 [main] INFO com.jcabi.aspects.aj.NamedThreads - jcabi-aspect 0.22.6 / 3f0a1f7 התחיל חוט דמון חדש jcabi-async לביצוע שיטה אסינכרונית 17: 46: 58.358 [jcabi-async] INFO com.baeldung.async.JavaAsync - #factorialUsingJc (20): '[מוגן בדוא"ל] [הושלם כרגיל]' ב 44.64 מיקרוגרם

אז אנו יכולים לראות שרשור דמון חדש jcabi-async נוצר על ידי הספרייה שביצעה את המשימה בצורה סינכרונית.

באופן דומה, הרישום מופעל על ידי @Loggable ביאור המסופק על ידי הספרייה.

7. מסקנה

במאמר זה ראינו כמה דרכים לתכנות אסינכרוני ב- Java.

ראשית, בדקנו את התכונות המובנות של Java כמו FutureTask ו העתיד לתכנות אסינכרוני. ואז ראינו כמה ספריות כמו EA Async ו- Cactoos עם פתרונות מהקופסה.

כמו כן, בדקנו את התמיכה בביצוע משימות בצורה אסינכרונית באמצעות גויאבה האזנה לעתיד ו עתיד שיעורים. אחרון, בדקנו את ספריית jcabi-AspectJ המספקת תכונות AOP באמצעותה @ Async ביאור לשיחות שיטה אסינכרונית.

כרגיל, כל יישומי הקוד זמינים ב- GitHub.