Vor einiger Zeit habe ich einen Beitrag über Java Callable Future-Schnittstellen geschrieben, die wir verwenden können, um die Vorteile der nebenläufigen Verarbeitung von Threads zu erhalten, da sie in der Lage sind, einen Wert an das aufrufende Programm zurückzugeben. FutureTask ist die grundlegende konkrete Implementierung des Future-Interfaces und bietet asynchrone Verarbeitung. Es enthält Methoden zum Starten und Abbrechen einer Aufgabe sowie Methoden, die den Status des FutureTask zurückgeben können, wie zum Beispiel, ob er abgeschlossen oder abgebrochen ist. Wir benötigen ein aufrufbares Objekt, um eine FutureTask zu erstellen, und dann können wir Java Thread Pool Executor verwenden, um diese Aufgaben asynchron zu verarbeiten. Schauen wir uns das Beispiel von FutureTask mit einem einfachen Programm an. Da FutureTask ein aufrufbares Objekt erfordert, werden wir eine einfache Callable-Implementierung erstellen.
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);
//den Thread-Namen zurückgeben, der diese aufrufbare Aufgabe ausführt
return Thread.currentThread().getName();
}
}
Hier ist ein Beispiel für die FutureTask-Methode und sie zeigt die häufig verwendeten Methoden von 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-Service herunterfahren
executor.shutdown();
return;
}
if(!futureTask1.isDone()){
//Unbegrenzt auf das Abschließen der FutureTask warten
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){
//Nichts tun
}
}
}
}
Wenn wir das obige Programm ausführen, werden Sie feststellen, dass für einige Zeit nichts gedruckt wird, weil die get()
-Methode von FutureTask darauf wartet, dass die Aufgabe abgeschlossen wird, und dann das Ausgabeobjekt zurückgibt. Es gibt auch eine überladene Methode, um nur eine bestimmte Zeit zu warten, und wir verwenden sie für futureTask2. Beachten Sie auch die Verwendung der isDone()
-Methode, um sicherzustellen, dass das Programm beendet wird, sobald alle Aufgaben ausgeführt sind. Die Ausgabe des obigen Programms wird sein:
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
In diesem Fall gibt es keinen Nutzen von FutureTask, aber es ist nützlich, wenn wir einige Methoden des Future-Interfaces überschreiben möchten und nicht jede Methode des Future-Interfaces implementieren möchten.
Source:
https://www.digitalocean.com/community/tutorials/java-futuretask-example-program