2015-07-20 14 views
6

Ich habe 3 FutureTask<T> Objekte. Ich möchte, dass sie asynchron verarbeitet werden. Sobald jedoch eine der get() Methoden von FutureTasks null nicht zurückgibt, möchte ich fortfahren, d. H. Meine Methode (Wrapper) kehrt zurück und wartet nicht, bis die anderen beiden FutureTasks verarbeitet wurden. Ich dachte an so etwas wie:Fortfahren, wenn eine zukünftige Aufgabe erwartet wird Ergebnis

private File wrapper(final File file) { 
    ExecutorService executors = Executors.newCachedThreadPool(); 
    File returnFile; 
    FutureTask<File> normal= ... 
    FutureTask<File> medium=...  
    FutureTask<File> huge=... 

    executors.execute(normal); 
    executors.execute(medium); 
    executors.execute(huge); 
    try { 
     if((returnFile=normal.get()) != null || 
      (returnFile=medium.get()) != null || 
      (returnFile=huge.get()) != null) 

      return returnFile; 

    } catch(ExecutionException | InterruptedException e) { } 
} 

Ich bin nicht sicher, wie die Ausnahmen zu erfassen (von der get geworfen()) in einem richtigen Weg, weil ich davon ausgehen, werden sie, da ich ohne gerade geworfen werden zurückkehren zu warten Die anderen beiden Aufgaben müssen erledigt werden. Außerdem habe ich Zweifel, dass der Code wie geplant funktioniert. Ich fühle, dass ich der Lösung nahe bin, aber etwas vermisse.

+0

Verwenden Sie Java 8? – John

+0

derzeit java 7 – Brenne

+0

dingy hier ist, dass Sie Ergebnis sofort für große Aufgabe verfügbar, aber Sie sind unnötig blockiert warten auf lange laufende Aufgabe normal. Wenn ich Ihre Anforderung richtig verstanden habe, reicht es aus, dass nur eine davon für die Verarbeitung abgeschlossen ist. – John

Antwort

1

Darf ich vorschlagen, nach FutureTask :: isDone zu suchen?

Wäre so etwas wie dieses dann:

while(true) { 
    if (normal.isDone()) { 
     return normal.get(); 
    } 
    if (medium.isDone()) { 
     return medium.get(); 
    } 
    if (huge.isDone()) { 
     return huge.get(); 
    } 
} 

EDIT: Sie könnten die anderen Aufgaben cancel, sobald Sie ein Ergebnis bei der Hand haben.

FutureTask::get Verwendung ist nicht das, was Sie suchen, da es höchstwahrscheinlich immer das Ergebnis von normal.get() zurückgeben, weil die Dokumentation schon heißt es:

Waits bei Bedarf für die Berechnung abgeschlossen ist, und dann ruft sein Ergebnis ab.

die oben Zur Klarstellung: Wenn Sie FutureTask verwenden :: die erste FutureTask Sie erhalten wird höchstwahrscheinlich Block nennen bekommen und warten, bis ein Ergebnis zurück zur Verfügung.

EDIT2:

Wrap, dass Schleife in eine neue Runnable, durch die ExecutorService ausgeführt, vorbei das erste Ergebnis an eine andere Methode zur Verfügung, oder einen Rückruf implementieren und es gibt nicht mehr beschäftigt warten.

+0

Beschäftigt warten? Was für ein Meisterwerk der Parallelverarbeitung! – Val

+1

Es war nicht meine Absicht, beschäftigtes Warten zu fördern. Ich habe gerade versucht, das Problem mit FutureTask :: get zu zeigen. :) Trotzdem, danke, dass du darauf hingewiesen hast! –

+0

Fügen Sie einen Link zum Abbrechen der Methodendokumentation hinzu http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/FutureTask.html#cancel%28boolean%29 –

0

Ich hatte eine Idee, es mit BlockingQueue zu entwerfen. Sie erweitern Ihre Aufgaben mit der done-Methode und senden Ergebnisse in BlockinQueue. Wenn der Client das erste Ergebnis erhalten hat, werden andere Aufgaben abgebrochen. Auf der anderen Seite, experts suggest using ExecutorCompletionService stattdessen. Es scheint zu serialisieren Ergebnisse imself und has all appropriate examples.