Enige tijd geleden schreef ik een bericht over Java Callable Future-interfaces die we kunnen gebruiken om de voordelen van gelijktijdige verwerking met threads te verkrijgen, terwijl ze ook in staat zijn om een waarde terug te geven aan het aanroepende programma. FutureTask is de basisconcrete implementatie van het Future-interface en biedt asynchrone verwerking. Het bevat methoden om een taak te starten en te annuleren, evenals methoden die de status van de FutureTask kunnen teruggeven, zoals of deze is voltooid of geannuleerd. We hebben een aanroepbaar object nodig om een toekomstige taak te maken, en dan kunnen we Java Thread Pool Executor gebruiken om deze asynchroon te verwerken. Laten we het voorbeeld van FutureTask bekijken met een eenvoudig programma. Aangezien FutureTask een aanroepbaar object vereist, zullen we een eenvoudige Callable-implementatie maken.
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);
// geef de naam van de thread terug die deze aanroepbare taak uitvoert
return Thread.currentThread().getName();
}
}
Hier is een voorbeeld van de FutureTask-methode en het toont veelgebruikte methoden van 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");
// sluit de uitvoerderservice af
executor.shutdown();
return;
}
if(!futureTask1.isDone()){
// wacht onbepaald op het voltooien van de toekomstige taak
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){
// doe niets
}
}
}
}
Wanneer we het bovenstaande programma uitvoeren, zul je merken dat het een tijdje niets afdrukt omdat de `get()` methode van FutureTask wacht tot de taak is voltooid en vervolgens het uitvoerobject retourneert. Er is ook een overbelaste methode om slechts een bepaalde tijd te wachten, en we gebruiken deze voor futureTask2. Let ook op het gebruik van de `isDone()` methode om ervoor te zorgen dat het programma wordt beëindigd zodra alle taken zijn uitgevoerd. De uitvoer van het bovenstaande programma zal zijn:
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
Zoals het er nu uitziet, heeft FutureTask geen direct voordeel, maar het is handig wanneer we enkele methoden van de Future-interface willen overschrijven en niet elke methode van de Future-interface willen implementeren.
Source:
https://www.digitalocean.com/community/tutorials/java-futuretask-example-program