2016-08-19 4 views
1

Ich habe ein Programm, in dem ich Dateien von S3 mit einem Callable-Objekt herunterladen, die an einen ExecutorService übergeben. Die Dateien sind groß und es dauert einige Minuten, bis sie vollständig heruntergeladen sind. Ist es sinnvoll, eine andere Callable-Klasse zu erstellen, die die Zukunft vom Downloader übernimmt und sie zur Fertigstellung betrachtet? Mein Endziel ist es, alle vollständigen Downloads zu einer zentralen Liste innerhalb eines Caches hinzuzufügen.Zukünftige <T> Objekte für die Fertigstellung mit ExecutorService

Zum Beispiel:

public void add(final String s3urlToDownload){ 

    Future<S3Object> futureS3obj = cachedPoolExecutor.submit(new S3Downloader(s3urlToDownload)); 

    // Instead of calling futureS3obj.get() and waiting, submit the Future to the "Watcher" service. 
    // Within FutureWatcher, the S3Object will be added to the List once the download is complete. 
    cachedPoolExecutor.submit(new FutureWatcher(downloadedList, futureS3obj)) 

} 
+0

Was ist der Vorteil eines zusätzlichen 'Callable', wenn Sie bereits eine' Zukunft' haben? – Kayaman

+0

@Kayaman, Zu meinem Verständnis, wenn ich die '' '()' '' Methode der Zukunft nannte, würde die 'add' Methode blockieren. Deshalb melde ich einen neuen Callable 'FutureWatcher' – dmux

+0

Also was bringt das' Callable' ins Spiel? Der Aufruf der 'call()' Methode würde ebenfalls blockieren, da es auf 'get()' delegiert wird. – Kayaman

Antwort

1

Hier sind einige gefälschte Objekte, die zur Illustration verwendet werden. "Downloads" sind nur zufällig Betten:

// for illustration only 
class S3Object { 
    String id; 
} 

// for illustration only 
class S3Downloader { 

    public S3Object download(String url) { 
     int min = 2; 
     int max = 5; 
     Random rand = new Random(); 
     int random = rand.nextInt((max - min) + 1) + min; 

     try { Thread.sleep(1000 * random); } catch (Exception ex) {} 
     S3Object result = new S3Object(); 
     result.id = url; 
     return result; 
    } 
} 

Wir haben eine Aufgabe definieren, die die Datei herunterlädt, aktualisiert eine (thread-safe) Liste, und dekrementiert ein CountDownLatch:

class MyTask implements Runnable { 
    private final List<S3Object> list; 
    private final CountDownLatch latch; 
    private final String url; 

    public MyTask(List<S3Object> list, CountDownLatch latch, String url) { 
     this.list = list; 
     this.latch = latch; 
     this.url = url; 
    }  

    public void run() { 
     S3Downloader downloader = new S3Downloader(); 
     S3Object result = downloader.download(url); 
     list.add(result); 
     latch.countDown(); 
    } 
} 

Ein Beispiel Runner zeigt der Kunde". Die go Methode ist der Fahrer, und verwendet die add Methode (die nicht blockiert):

public class Runner { 
    private ExecutorService pool = Executors.newCachedThreadPool(); 
    private int numUrls = 20; 
    private CountDownLatch latch = new CountDownLatch(numUrls); 
    private List<S3Object> results = Collections.synchronizedList(new ArrayList<S3Object>()); 

    public void add(String url) { 
     pool.submit(new MyTask(results, latch, url)); 
    } 

    public void go() throws Exception { 

     for(int i = 0; i < numUrls; i++) { 
      String url = "http://example" + i; 
      add(url); 
     } 

     // wait for all downloads 
     latch.await(); 

     for (S3Object result : results) { 
      System.out.println("result id: " + result.id); 
     } 
    } 
} 

Produktionscode muss Fehler behandeln und möglicherweise den Client entsprechend reorganisieren.

+0

Dank Michael, ich sollte in der Lage sein, meinen Code umzuformen, um das obige Framework einzuschließen. – dmux

0

Statt einen ‚Beobachter‘ zu machen, die Ressourcen verbraucht, machen die aktuellen Downloads den Master nach Abschluss informieren.

Verwandte Themen