2015-06-22 16 views
8

Ci sono due approcci per la presentazione e il compito di polling per il risultatoqual è il vantaggio di utilizzare FutureTask su Callable?

FutureTask futureTask = new FutureTask<String>(callable); 
  1. Uso combinazione di Callable e Future e presentare una proposta in ExecutorService. Recupera il risultato utilizzando future.get().

    Future future = service.submit(callable); 
    
  2. Usa FutureTask. Ciò avvolgerà Callable e quindi recupererà il risultato utilizzando FutureTask.

    service.execute(task); 
    

Qual è il vantaggio di utilizzare FutureTask sopra Callable + combinazione futuro?

+0

Il FutureTask implementa l'interfaccia Future, quindi quale è esattamente la differenza tra gli approcci in termini concreti? (esempio mostra un esempio) –

+0

Task FutureTask = new FutureTask (richiamabile); \t \t // Implementazione 1 \t \t Fut Fut = service.submit (callable); \t \t // Implementazione 2. \t servizio \t.eseguire (task); perché dovremmo preferire l'implementazione 1 sull'implementazione 2. C'è qualche vantaggio? –

+2

Non inserire il codice nei commenti, aggiornare la risposta. –

risposta

4

Quasi certamente nessuno. Una rapida ricerca su GrepCode di AbstractExecutorService mostra che ognuno di questi metodi sono semplicemente metodi di supporto che alla fine avvolgono il Callable/Runnable in un Future per te.

protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) { 
    return new FutureTask<T>(runnable, value); 
} 

protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) { 
    return new FutureTask<T>(callable); 
} 

public Future<?> submit(Runnable task) { 
    // ... 
    RunnableFuture<Object> ftask = newTaskFor(task, null); 
    execute(ftask); 
    return ftask; 
} 

public <T> Future<T> submit(Runnable task, T result) { 
    // ... 
    RunnableFuture<T> ftask = newTaskFor(task, result); 
    execute(ftask); 
    return ftask; 
} 

public <T> Future<T> submit(Callable<T> task) { 
    // ... 
    RunnableFuture<T> ftask = newTaskFor(task); 
    execute(ftask); 
    return ftask; 
} 
4

Utilizzando Future possiamo scoprire lo stato dell'attività Callable e ottenere l'oggetto restituito. Fornisce il metodo get() che può aspettare che il Callable termini e quindi restituire il risultato.

Future fornisce il metodo cancel() per annullare l'attività Callable associata. Esiste una versione sovraccaricata del metodo get() in cui è possibile specificare il tempo di attesa del risultato, è utile evitare che il thread corrente venga bloccato per un tempo più lungo. Esistono i metodi isDone() e isCancelled() per scoprire lo stato corrente dell'attività Callable associata.

Ecco un semplice esempio di attività Callable che restituisce il nome del thread che esegue l'attività dopo un secondo. Utilizziamo il framework Executor per eseguire 100 attività in parallelo e utilizzare Future per ottenere il risultato delle attività inoltrate.

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<String> { 

     @Override 
     public String call() throws Exception { 
      Thread.sleep(1000); 
      //return the thread name executing this callable task 
      return Thread.currentThread().getName(); 
     } 

     public static void main(String args[]){ 
      //Get ExecutorService from Executors utility class, thread pool size is 10 
      ExecutorService executor = Executors.newFixedThreadPool(10); 
      //create a list to hold the Future object associated with Callable 
      List<Future<String>> list = new ArrayList<Future<String>>(); 
      //Create MyCallable instance 
      Callable<String> callable = new MyCallable(); 
      for(int i=0; i< 100; i++){ 
       //submit Callable tasks to be executed by thread pool 
       Future<String> future = executor.submit(callable); 
       //add Future to the list, we can get return value using Future 
       list.add(future); 
      } 
      for(Future<String> fut : list){ 
       try { 
        //print the return value of Future, notice the output delay in console 
        // because Future.get() waits for task to get completed 
        System.out.println(new Date()+ "::"+fut.get()); 
       } catch (InterruptedException | ExecutionException e) { 
        e.printStackTrace(); 
       } 
      } 
      //shut down the executor service now 
      executor.shutdown(); 
     } 
    } 

Dove come FutureTask è la base concreta dell'interfaccia futuri e fornisce elaborazione asincrona. Contiene i metodi per avviare e annullare un'attività e anche i metodi che possono restituire lo stato del FutureTask come se sia stato completato o annullato. Abbiamo bisogno di un oggetto callable per creare un'attività futura e quindi possiamo utilizzare Java Thread Pool Executor per elaborarli in modo asincrono.

Vediamo l'esempio di FutureTask con un semplice programma.

Poiché FutureTask richiede un oggetto callable, creeremo una semplice implementazione Callable.

public class MyCallable implements Callable<String> { 

    private long waitTime; 

    public MyCallable(int timeInMillis){ 
     this.waitTime=timeInMillis; 
    } 
    @Override 
    public String call() throws Exception { 
     Thread.sleep(waitTime); 
     //return the thread name executing this callable task 
     return Thread.currentThread().getName(); 
    } 

} 

    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<String> futureTask1 = new FutureTask<String>(callable1); 
     FutureTask<String> futureTask2 = new FutureTask<String>(callable2); 

     ExecutorService executor = Executors.newFixedThreadPool(2); 
     executor.execute(futureTask1); 
     executor.execute(futureTask2); 

     while (true) { 
      try { 
       if(futureTask1.isDone() && futureTask2.isDone()){ 
        System.out.println("Done"); 
        //shut down executor service 
        executor.shutdown(); 
        return; 
       } 

       if(!futureTask1.isDone()){ 
       //wait indefinitely for future task to complete 
       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){ 
       //do nothing 
      } 
     } 

    } 

} 
+0

Queste sono solo differenze API. Funzionalmente, FutureTask non sembra offrire alcun vantaggio. –

+0

Piuttosto che un vantaggio è più farlo con l'utilità e il requisito della situazione. Dovresti solo usare FutureTask se vuoi cambiarne il comportamento o accedere più tardi a Callable ma un buon motivo per lasciare che l'Executor costruisca il FutureTask per te è assicurarsi che non ci sia modo più di un riferimento all'esistente FutureTask . Cioè, l'esecutore possiede questa istanza. Maggioranza dei tempi, usiamo Callable e Future. – Mudassar