Java Callable ו־Future משמשים הרבה בתכנות מרובה-תרשימי. בפוסטים האחרונים, למדנו הרבה על תהליכי גרעין של Java אבל לעיתים נרצה שלתהליך תהיה אפשרות להחזיר ערך שנוכל להשתמש בו. בגרסה 5 של Java הוכנס הממשק java.util.concurrent.Callable בחבילת המקביליות המכיל ממשק Runnable אך הוא יכול להחזיר כל אובייקט ולזרוק חריגה.
Java Callable
ממשק Java Callable משתמש בגנריק להגדרת סוג ההחזר של האובייקט. מחלקת Executors מספקת שיטות שימושיות לביצוע Java Callable בבריכת תהליכים. מאחר ומשימות callable רצות בפרלליזם, עלינו להמתין לאובייקט המוחזר.
Java Future
המשימות Callable של Java מחזירות אובייקט java.util.concurrent.Future. באמצעות אובייקט Java Future, אנו יכולים לגלות את מעמד המשימה Callable ולקבל את האובייקט שהוחזר. זה מספק את השיטה get() שיכולה להמתין להשלמת ה-Callable ולאח"כ להחזיר את התוצאה. Java Future מספקת את השיטה cancel() לביטול המשימה Callable המתאימה. יש גרסה מעודכנת של שיטת get() בה ניתן לציין את הזמן שיש להמתין לתוצאה, זה שימושי למניעת חסימת התהליך הנוכחי לזמן רב יותר. ישנן שיטות isDone() ו־isCancelled() לגילוי המעמד הנוכחי של משימת Callable המתאימה. הנה דוגמה פשוטה של משימת Callable של Java שמחזירה את שם התהליך המבצע את המשימה לאחר שנייה אחת. אנו משתמשים ב־Executor framework כדי לבצע 100 משימות במקביל ומשתמשים ב־Java Future כדי לקבל את התוצאה של המשימות שהוגשו.
package com.journaldev.threads;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class MyCallable implements Callable {
@Override
public String call() throws Exception {
Thread.sleep(1000);
//החזר את שם התהליך המבצע את המשימה הזו
return Thread.currentThread().getName();
}
public static void main(String args[]){
//קבל ExecutorService מהמחלקה Executors, גודל הגלאי הוא 10
ExecutorService executor = Executors.newFixedThreadPool(10);
//צור רשימה לאחסון את אובייקטי ה-Future הקשורים ל-Callable
List> list = new ArrayList>();
//צור אובייקט MyCallable
Callable callable = new MyCallable();
for(int i=0; i< 100; i++){
//שלח משימות Callable לביצוע על ידי גלאי הגידול
Future future = executor.submit(callable);
//הוסף את Future לרשימה, נוכל לקבל את ערך ההחזרה באמצעות Future
list.add(future);
}
for(Future fut : list){
try {
//הדפס את ערך ההחזרה של Future, שים לב להשהייה בקונסול, מכיוון ש- Future.get() מחכה למשימה להשלים
//בגלל ש- Future.get() מחכה למשימה להשלים
System.out.println(new Date()+ "::"+fut.get());
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
//כבה את שירות הביצוע כעט כעט
executor.shutdown();
}
}
לאחר ביצוע התוכנית לעיל, תשים לב להשהייה בהפלט מכיוון ש- get() של Future ב-Java מחכה למשימת Callable להשלים. שים לב שיש רק 10 תהליכים שמבצעים את המשימות. כאן חלק מתפקיד פלט התוכנית למעלה
Mon Dec 31 20:40:15 PST 2012::pool-1-thread-1
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-2
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-3
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-4
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-5
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-6
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-7
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-8
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-9
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-10
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-2
...
עצה: מה לעשות אם נרצה לדרוס חלק מהשיטות של ממשק Java Future, לדוג לדרוס את get()
כדי לקבוע זמן מותר במקום לחכות לזמן בלתי מוגבל, במקרה כזה משמשת המחלקה Java FutureTask שהיא המימוש הבסיסי של ממשק Future. בדוק את דוגמה ל- Java FutureTask כדי לדעת עוד על מחלקה זו.
Source:
https://www.digitalocean.com/community/tutorials/java-callable-future-example