sabato 5 aprile 2014

Callable vs Runnable

In Java dalla versione 1.0 è presente l'interfaccia java.lang.Runnable, che come sappiamo deve essere implementata da quelle classi che si vuole eseguire come Thread separati.
Nell'interfaccia è dichiarato un solo metodo

void run()

Dalla versione 1.5 invece è stata creata una nuova interfaccia java.util.concurrent.Callable che per certi versi può essere vista come una estensione dell'interfaccia Runnable. Lo scopo dei progettisti è sempre quello di mantenere la retrocompatibilità, e questo è il motivo per cui non hanno modificato l'interfaccia Runnable ma ne hanno creata una nuova.

L'unico metodo definito dall'interfaccia Callable è:

V call() throws Exception

Il vantaggio di utilizzare Callable è che consente di ottenere indietro il risultato dell'esecuzione del task nel thread separato, cosa che tramite Runnable non è possibile.
In generale le differenze tra le 2 interfacce sono le seguenti:

  1. Un oggetto che implementa Callable non può essere utilizzato direttamente per costruire un Thread, mentre un oggetto che implementa Runnable può farlo;
  2. Un oggetto che implementa  Callable torna un risultato mentre un oggetto che implementa Runnable no;
  3. Un  oggetto che implementa Callable può rilanciare al chiamante una eccezione di tipo checked, mentre un oggetto che implementa Runnable può lanciare soltanto unchecked exceptions.
Vediamo un esempio di utilizzo di Callable.
Per utilizzare un oggetto che implementa un Callable dobbiamo necessariamente utilizzare un ExecutorService.

CALLABLE

import java.util.concurrent.Callable;
public class Fattoriale implements Callable<Long> {
 private long n;
 public Fattoriale(long n){
 this.n=n; 
 }
 @Override
 public Long call() throws Exception {
  
  if(n<=0) throw new Exception("Attenzione inserire un valore positivo!!");
  long f=1;
  for(long i=1;i<=n;i++){
   f*=i;
  }
  return f;
 }
}

EXECUTORSERVICE

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class FattorialeTest {
 public static void main(String[] args) throws Exception {
       long N=5;
       Callable<Long> c=new Fattoriale(N);
       ExecutorService es=Executors.newSingleThreadExecutor();
       Future<Long> f=es.submit(c);
       System.out.println(String.format("Il fattoriale di %d è %d",N,f.get()));
       es.shutdown();
 }
}


Si noti che l'executor service funziona anche con oggetti di tipo Runnable ma, poichè questi non tornano un risultato, il Future associato tornerà null se il processo è terminato correttamente.

Nessun commento:

Posta un commento