2017-10-09 3 views
0

javafx.concurrent.Task과 함께 수행 할 수있는 작업은 java.util.concurrent.CallableExecutorService.invokeAll(Collection<? extends Callable<T>>)으로 수행 할 수 있습니다.이 메소드는 실행 가능 파일이며 호출 가능하지 않은 태스크와 함께 사용할 수 없습니다.Java Invoke 태스크 콜렉션 (invokeAll과 동일)

반환 할 Callable이 항상 null을 반환하고 Task.call()에서 반환 된 값이 필요하기 때문에 호출 가능 항목 인 내 작업 유형을 Executors.callable(Runnable task)으로 캐스팅하지 못했습니다.

TaskCollections에서 사용하도록 설계되지 않았 음을 이해합니다. 그러나 JavaFX 응용 프로그램에 Task이 필요하며 테스트를 작성하여이 문제에 부딪 힙니다.

단순히 내 TaskCallable으로 구현하는 것 이외의 다른 방법을 피할 수있는 방법이 있습니까? 나는 그때 내 테스트에 맞는 코드를 바꿀 것이기 때문에 나는하고 싶지 않다.

+0

당신은 한 지점에서 'Runnable'을, 다른 지점에서는 'Callable'에 대해 이야기하고 있습니다. 귀하의 질문을 다시 작성하여 현재보다 훨씬 명확합니다. 또한, Task가'Callable'을 구현하게 만드는 것에있어 잘못된 점을 설명하십시오. – Kayaman

+0

나는 그랬다. 문제를 더 잘 이해 하는가? –

+0

예, 여기에서 https://bugs.openjdk.java.net/browse/JDK-8166449에서'Callable'을 구현하는 것이 그리 좋은 생각이 아님을 알 수 있습니다. 차이점을 강조하기 위해 질문을 편집했습니다. – Kayaman

답변

1

각 작업을 호출 가능하도록 둘 수 있습니다. 다음과 같이 기본적으로 각 Task<T> task을 위해, 당신은 Callable<T>이 필요합니다

Callable<T> callable =() -> { 
    task.run(); 
    return task.getValue(); 
}; 

따라서, 예를 들어, 당신은 당신이 할 수있는 Collection<Task<T>> tasks 다음

Function<Task<T>, Callable<T>> taskWrapper = task ->() -> { 
    task.run(); 
    return task.getValue(); 
}; 

과는 ExecutorService exec 주어진이 매핑을 수행하는 Function<Task<T>, Callable<T>>을 정의 할 수 있습니다 여기

List<Future<T>> results = exec.invokeAll(tasks.stream() 
    .map(taskWrapper) 
    .collect(Collectors.toList())); 

은 SSCCE입니다 :

import java.util.ArrayList; 
import java.util.List; 
import java.util.Random; 
import java.util.concurrent.Callable; 
import java.util.concurrent.ExecutorService; 
import java.util.concurrent.Executors; 
import java.util.concurrent.Future; 
import java.util.function.Function; 
import java.util.stream.Collectors; 

import javafx.application.Application; 
import javafx.concurrent.Task; 
import javafx.geometry.Insets; 
import javafx.geometry.Pos; 
import javafx.scene.Scene; 
import javafx.scene.control.Button; 
import javafx.scene.control.Label; 
import javafx.scene.layout.VBox; 
import javafx.stage.Stage; 

public class InvokeAllTasks extends Application { 

    private Random rng = new Random(); 
    private ExecutorService exec = Executors.newFixedThreadPool(5); 
    private Function<Task<Integer>, Callable<Integer>> taskWrapper = task ->() -> { 
     task.run(); 
     return task.getValue(); 
    }; 

    @Override 
    public void start(Stage primaryStage) { 
     Button runAll = new Button("Run all tasks"); 
     Label status = new Label(); 

     runAll.setOnAction(e -> { 
      List<Task<Integer>> tasks = createTasks(); 


      Task<List<Future<Integer>>> runAllTask = new Task<List<Future<Integer>>>() { 
       @Override 
       protected List<Future<Integer>> call() throws Exception { 
        return exec.invokeAll(tasks.stream().map(taskWrapper).collect(Collectors.toList())); 
       } 
      }; 
      status.setText("Running..."); 
      runAllTask.setOnSucceeded(evt -> status.setText("All Done")); 
      new Thread(runAllTask).start(); 


     }); 

     VBox root = new VBox(5, runAll, status); 
     root.setMinHeight(120); 
     root.setAlignment(Pos.CENTER); 
     root.setPadding(new Insets(10)); 

     Scene scene = new Scene(root); 
     primaryStage.setScene(scene); 
     primaryStage.show(); 
    } 

    @Override 
    public void stop() { 
     exec.shutdown(); 
    } 

    private List<Task<Integer>> createTasks() { 
     List<Task<Integer>> tasks = new ArrayList<>(); 
     for (int i = 1 ; i <= 8 ; i++) { 
      String name = "Task "+i; 
      Task<Integer> t = new Task<Integer>() { 
       @Override 
       protected Integer call() throws Exception { 
        System.out.println(name+" running"); 
        Thread.sleep(rng.nextInt(1000)+500); 
        int result = rng.nextInt(500); 
        System.out.println(name+" computed "+result); 
        return result; 
       } 
      }; 
      tasks.add(t); 
     } 
     return tasks; 
    } 

    public static void main(String[] args) { 
     launch(args); 
    } 
} 
+0

나는 이것을 많이 읽으면서 잠시 후에 다시 읽었다. 내가 이해하지 못하는 한 가지가 있습니다. 레이블 값을 계산할 때 레이블 상태가 "모두 완료"로 설정된 이유는 무엇입니까? –

+0

@ J.Ober ['ExecutorService.invokeAll()'] (https://docs.oracle.com/javase/9/docs/api/java/util/concurrent/ExecutorService.html#invokeAll-java.util.Collection) -)는 전달 된 모든 호출 가능 객체가 완료 될 때까지 차단하므로 모든 개별 태스크가 완료되면'runAllTask'가 정확하게'SUCCEEDED' 상태가됩니다. –