2017-10-09 6 views
0

で行うことができるもの、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

あなたは、ある時点では「実行可能」、別の時点では「呼び出し可能」について話しています。あなたの質問を書き換えて、それが現在のものよりはるかに明確になるようにしてください。また、タスクを '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'状態になります。 –

関連する問題