Java Callable en Future worden veel gebruikt in multithreaded programmeren. In de laatste paar berichten hebben we veel geleerd over Java-threads, maar soms willen we dat een thread een waarde kan retourneren die we kunnen gebruiken. Java 5 introduceerde de java.util.concurrent.Callable-interface in het concurrency-pakket, die vergelijkbaar is met de Runnable-interface, maar die elk object kan retourneren en een uitzondering kan gooien.
Java Callable
Java Callable-interface gebruikt generics om het retourtype van het object te definiëren. De klasse Executors biedt handige methoden om Java Callable uit te voeren in een threadpool. Aangezien callable taken parallel worden uitgevoerd, moeten we wachten op het retourneerde object.
Java Future
Java Callable-taken retourneren een java.util.concurrent.Future-object. Met behulp van het Java Future-object kunnen we de status van de Callable-taak achterhalen en het geretourneerde object verkrijgen. Het biedt de get()-methode die kan wachten tot de Callable-taak is voltooid en vervolgens het resultaat retourneert. Java Future biedt de cancel()-methode om de bijbehorende Callable-taak te annuleren. Er is een overbelaste versie van de get() methode waarin we de wachttijd voor het resultaat kunnen specificeren; dit is handig om te voorkomen dat de huidige thread voor langere tijd wordt geblokkeerd. Er zijn ook de methoden isDone() en isCancelled() om de huidige status van de bijbehorende Callable-taak te achterhalen. Hier is een eenvoudig voorbeeld van een Java Callable-taak die de naam van de thread retourneert die de taak uitvoert na één seconde. We gebruiken het Executor-framework om 100 taken parallel uit te voeren en gebruiken Java Future om het resultaat van de ingediende taken te verkrijgen.
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);
// Geef de naam van het uitvoerende thread dat deze oproepbare taak uitvoert
return Thread.currentThread().getName();
}
public static void main(String args[]){
// Haal ExecutorService op vanuit het hulpprogramma Executors, de grootte van de threadpool is 10
ExecutorService executor = Executors.newFixedThreadPool(10);
// Maak een lijst om het Future-object bij te houden dat is gekoppeld aan Callable
List> list = new ArrayList>();
// Maak een instantie van MyCallable
Callable callable = new MyCallable();
for(int i=0; i< 100; i++){
// Dien Callable-taken in om uitgevoerd te worden door de threadpool
Future future = executor.submit(callable);
// Voeg Future toe aan de lijst, we kunnen de retourwaarde krijgen met behulp van Future
list.add(future);
}
for(Future fut : list){
try {
// Druk de retourwaarde van Future af, let op de vertraging in de uitvoer in de console
// omdat Future.get() wacht tot de taak is voltooid
System.out.println(new Date()+ "::"+fut.get());
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
// Sluit nu de executor-service af
executor.shutdown();
}
}
Als we het bovenstaande programma uitvoeren, zul je merken dat er vertraging is in de uitvoer omdat de java Future get() methode wacht op de java oproepbare taak om te voltooien. Let ook op dat er slechts 10 threads zijn die deze taken uitvoeren. Hier is een fragment van de uitvoer van het bovenstaande programma.
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
...
Tip: Wat als we sommige van de methoden van de Java Future-interface willen overschrijven, bijvoorbeeld het overschrijven van get()
methode om na een standaardtijd time-out te krijgen in plaats van onbepaald te wachten, in dit geval komt Java FutureTask klasse van pas, dat is de basismethode van de Future-interface. Bekijk Java FutureTask voorbeeld om meer te weten te komen over deze klasse.
Source:
https://www.digitalocean.com/community/tutorials/java-callable-future-example