2016-03-18 4 views
2

Ich bin ein Programm zur Erzeugung von fraktalen und fraktale Animation zu schreiben, ist das Problem auf die Animation ...Warum Zukunft isDone() blockiert das Programm wie Future get()?

ich einen Haupt-Thread haben, die eine List<Callable<Long>> tasks erzeugen, wobei jedes Element die Informationen und Ressourcen für die Erzeugung eines Rahmens hat; Dann benutze ich eine ExecutorService, um die Arbeit einzureichen.

Das Problem liegt in der Unmöglichkeit, diese sekundären Thread abzubrechen, wenn der Benutzer den Kalkül stoppen möchte. Hier ist der Code:

public class Animation extends Task<Long> { 
protected Long call() throws Exception { 
    long startTime = System.currentTimeMillis(); 

    WritableImage[] frames = new WritableImage[frameNumber]; 
    List<Callable<Long>> tasks = new ArrayList<>(); 

    updateProgress(count.incrementAndGet(), maxCount); 
    if (isCancelled()) { 
     return System.currentTimeMillis() - startTime;; 
    } 

    for (int k = 0; k < frameNumber; k++) { 
     frames[k] = new WritableImage(
       (int) start.getCartesianPlane().getWidth(), 
       (int) start.getCartesianPlane().getHeight()); 

     CartesianFractal tmp = FractalFactory.bulidFractal(
       selectedFractal, nextDataBox(k), colorPalette); 

     tmp.setOnFinish(t -> { 
      updateProgress(count.incrementAndGet(), maxCount); 
      return null; 
     }); 

     tasks.add((Callable<Long>) tmp); 
     if (isCancelled()) { 
      return System.currentTimeMillis() - startTime;; 
     } 
    } 

    executor = Executors.newFixedThreadPool(4); 
    updateProgress(count.incrementAndGet(), maxCount); 
    if (isCancelled()) { 
     return System.currentTimeMillis() - startTime; 
    } 
    try { 
     result = executor.invokeAll(tasks); 
    } 
    catch (InterruptedException ex) { 
     System.err.println(ex.toString()); 
    } 

    // Check if all tasks are finished 
    boolean finished = false; 
    while (!finished) { 
     finished = true; 
     // Check if it is all done 
     for (Future<Long> r : result) { 
      finished = finished && r.isDone(); // THE PROGRAM BLOCKS HERE 
      // Check if the task was cancelled 
      if (isCancelled()) { 
       // Cancell all task 
       tasks.stream().forEach((t) -> { 
        ((CartesianFractal)t).myCancel(); 
       }); 
       // Turnoff the executor 
       executor.shutdown(); 
       return System.currentTimeMillis() - startTime; 
      } 
     } 
    } 

    // Turnoff the executor 
    executor.shutdown(); 
    updateProgress(count.incrementAndGet(), maxCount); 

    makeAnimation(); 
    updateProgress(count.incrementAndGet(), maxCount); 

    return System.currentTimeMillis() - startTime; 
} 
} 

ich nicht wirklich verstanden, warum Future.isDone() das Programm wie Future.get() blockieren!

Das ist meine erste Frage, also hoffe ich, dass alles in Ordnung ist.

+1

es funktioniert * wirklich * blocken dort (wie im Thread ist in "BLOCKED" Zustand), oder scheint es nur auf dieser Linie gestoppt werden, weil es beschäftigt ist - warten? –

+1

Übrigens ist ein 'CompletionService' möglicherweise eine einfachere Möglichkeit, benachrichtigt zu werden, wenn ein Thread fertig ist. –

+1

Ein anderer BTW: anstatt 'system.currentTimeMillis() - startTime; return 'zurückzugeben, können Sie den größten Teil der Logik in' void callInternal() 'aufteilen, die von' call() {long startTime = aufgerufen wird ...; callInternal(); Zurückgeben von System.currentTimeMillis() - startTime; } '. Ziehen Sie auch in Erwägung, 'executor.shutDown()' in einen einzigen 'finally' Block zu setzen. –

Antwort

1

Ich denke, dass es einfacher sein könnte, wenn Sie dies mit einer CompletionService implementiert, die Sie Future s in der Reihenfolge, die sie abgeschlossen sind.

Zum Beispiel:

Executor executor = Executors.newFixedThreadPool(4); 

try { 
    CompletionService completionService = new ExecutorCompletionService(executor); 

    List<Future<Long>> futures = new ArrayList<>(); 
    for (Callable<Long> task : task) { 
    futures.add(completionService.submit(task)); 
    } 

    int pending = futures.size(); 
    while (pending > 0) { 
     // Wait for up to 100ms to see if anything has completed. 
     // The completed future is returned if one is found; otherwise null. 
     // (Tune 100ms as desired) 
     Future<Long> completed = completionService.poll(100, TimeUnit.MILLISECONDS); 
     if (completed != null) { 
      updateProgress(count.incrementAndGet(), maxCount); 
      --pending; 
    } 
    if (isCancelled()) { 
     // Cancel all task etc. 
     break; 
    } 
    } 
} finally { 
    executor.shutdown(); 
} 
0

Dank für die Zeit und helfen Sie mir geben müssen!

Das Programm scheint nur damit beschäftigt zu sein, so habe ich diese Lösung gefunden: für Löschen aller Jobs i verwenden Sie diesen Code:

if (task != null) { 
    task.myCancel(); 
    task.cancel(); 
} 

Während die Animation Klasse geworden:

public class Animation extends Task<Long> { 
[...] 
@Override 
protected Long call() throws Exception { 
    long startTime = System.currentTimeMillis(); 
    ExecutorService executor = null; 

    try { 
     frames = new WritableImage[frameNumber]; 
     updateProgress(count.incrementAndGet(), maxCount); 
     if (isCancelled()) { 
      return System.currentTimeMillis() - startTime; 
     } 

     executor = Executors.newWorkStealingPool(); 
     //executor = Executors.newFixedThreadPool(4); 
     updateProgress(count.incrementAndGet(), maxCount); 
     if (isCancelled()) { 
      return System.currentTimeMillis() - startTime; 
     } 

     tasks = initTasks(); 
     updateProgress(count.incrementAndGet(), maxCount); 
     if (isCancelled()) { 
      return System.currentTimeMillis() - startTime; 
     } 

     result = executor.invokeAll(tasks); 
     updateProgress(count.incrementAndGet(), maxCount); 

     makeAnimation(); 
     updateProgress(count.incrementAndGet(), maxCount); 
    } 
    catch (InterruptedException ex) { 
     System.err.println(ex.toString()); 
    } 
    finally { 
     if (executor != null) { 
      executor.shutdown(); 
     } 
    } 

    return System.currentTimeMillis() - startTime; 
} 
[...] 
public void myCancel() { 
    tasks.stream().forEach((t) -> { 
     ((CartesianFractal)t).myCancel(); 
    }); 
} 
[...] 
} 
Verwandte Themen