לפני זמן קצר כתבתי פוסט על ממשקי Java Callable Future שאנו יכולים להשתמש בהם כדי לקבל את היתרונות בעיבוד קונקורנטי של תהליכים וכמו כן הם מסוגלים להחזיר ערך לתכנית הקוראת. FutureTask הוא מימוש בסיסי של ממשק Future ומספק עיבוד אסינכרוני. זה מכיל את השיטות להתחלת וביטול משימה וגם שיטות שיכולות להחזיר את מצב ה-FutureTask כמו שהוא הושלם או בוטל. אנו צריכים אובייקט callable כדי ליצור משימת עתיד ואז אנו יכולים להשתמש ב-Java Thread Pool Executor כדי לעבד אותם אסינכרונית. בואו נראה את דוגמת השימוש של FutureTask עם תוכנית פשוטה. מאחר ו-FutureTask דורשת אובייקט callable, ניצור יישום Callable פשוט.
package com.journaldev.threads;
import java.util.concurrent.Callable;
public class MyCallable implements Callable {
private long waitTime;
public MyCallable(int timeInMillis){
this.waitTime=timeInMillis;
}
@Override
public String call() throws Exception {
Thread.sleep(waitTime);
// החזרת שם התהליך שמבצע את המשימה הזו הניתנת לקריאה
return Thread.currentThread().getName();
}
}
כאן דוגמה לשיטת FutureTask והיא מציגה שימושים נפוצים של שיטות FutureTask.
package com.journaldev.threads;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
public class FutureTaskExample {
public static void main(String[] args) {
MyCallable callable1 = new MyCallable(1000);
MyCallable callable2 = new MyCallable(2000);
FutureTask futureTask1 = new FutureTask(callable1);
FutureTask futureTask2 = new FutureTask(callable2);
ExecutorService executor = Executors.newFixedThreadPool(2);
executor.execute(futureTask1);
executor.execute(futureTask2);
while (true) {
try {
if(futureTask1.isDone() && futureTask2.isDone()){
System.out.println("Done");
// כיבוי שירותי הביצוע
executor.shutdown();
return;
}
if(!futureTask1.isDone()){
// המתן ללא הגבלה זמן למשימה העתידית להשלים
System.out.println("FutureTask1 output="+futureTask1.get());
}
System.out.println("Waiting for FutureTask2 to complete");
String s = futureTask2.get(200L, TimeUnit.MILLISECONDS);
if(s !=null){
System.out.println("FutureTask2 output="+s);
}
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}catch(TimeoutException e){
// לא לעשות דבר
}
}
}
}
כאשר אנו מפעילים את התוכנית שנמצאת למעלה, תישים לב שאין הדפסה של כלום לזמן מסוים מכיוון ששיטת get()
של FutureTask ממתינה למשימה להשלים ואז מחזירה את אובייקט הפלט. קיימת גם שיטה מוטעמת נוספת להמתנה לפרק זמן מסוים בלבד, ואנו משתמשים בה עבור futureTask2. כמו כן, שים לב לשימוש בשיטת isDone()
כדי לוודא שהתוכנית מסתיימת כשכל המשימות מבוצעות. פלט של התוכנית שנמצאת למעלה יהיה:
FutureTask1 output=pool-1-thread-1
Waiting for FutureTask2 to complete
Waiting for FutureTask2 to complete
Waiting for FutureTask2 to complete
Waiting for FutureTask2 to complete
Waiting for FutureTask2 to complete
FutureTask2 output=pool-1-thread-2
Done
ככה אין יתרון ב־FutureTask אבל הוא מועיל כאשר רוצים לדרוס חלק משיטות הממשק של Future ולא רוצים ליישם כל שיטת ממשק של Future.
Source:
https://www.digitalocean.com/community/tutorials/java-futuretask-example-program