في وقت سابق، كتبت مقالًا حول واجهات 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