Title: JavaFX Task Callable
Tags: java;multithreading;javafx
Question: I was developing a JavaFX app and I was supplying the JavaFX tasks in an ExecutorService submit method. Also I was trying to get the return value of the Task in the return value of the submit in a Future object. Then I discovered that ExecutorService only returns value when you submit a Callable object, and JavaFX Tasks are runnables despite having a call method. so is there any workaround for this problem?
I tried and solved my problem this way but I'm open to suggestions when I don't want to write my own class.
My main method:
public static void main(String[] args) throws InterruptedException, ExecutionException {
ExecutorService executorService = Executors.newSingleThreadExecutor();
Semaphore semaphore = new Semaphore(1);
List<Integer&gt; list = IntStream.range(0,100).boxed().collect(Collectors.toList());
Iterator<Integer&gt; iterator = list.iterator();
while (iterator.hasNext()){
List<Integer&gt; sendingList = new ArrayList<&gt;();
for (int i = 0; i < 10; i++) {
sendingList.add(iterator.next());
}
System.out.println("SUBMITTING");
Future<Integer&gt; future = executorService.submit((Callable<Integer&gt;) new TestCallable(sendingList,semaphore));
System.out.println(future.get());
semaphore.acquire();
executorService.shutdown();
System.out.println("COMPLETED");
My TestCallable class:
class TestCallable extends Task<Integer&gt; implements Callable<Integer&gt; {
private Random random = new Random();
private List<Integer&gt; list;
private Semaphore semaphore;
TestCallable(List<Integer&gt; list, Semaphore semaphore) {
this.list = list;
this.semaphore = semaphore;
@Override
public Integer call(){
System.out.println("SENDING");
System.out.println(list);
try {
Thread.sleep(1000+random.nextInt(500));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("RECEIVED");
semaphore.release();
return list.size();
Comment: You do notice that a) `Task` implements `Future` b) submitting the task and immediately calling `get` results in waiting in the calling thead waiting for the completion of the task. You just could have executed the task on the thread directly.

Comment: Calling `Future.get` you make sure to wait until the task is completed. Assuming the same priority for the submitting thread and the thread executing the task, running the task on a different thread is not faster and it does not result in any of the tasks from running in parallel even with a multi-threaded executor. Submitting a task in this scenario moves the work from one thread to another thread and keeps the submitting task busy waiting for the completion of the task...

Comment: what if I have a multi-thread executor and I want to wait if there is no thread available, not for each task?


Here is another answer: It's not very clear what you want to do here.
Firstly, your Semaphore does nothing because you used Executors.newSingleThreadExecutor(), which already guarantees that only one task can run at any point in time.
Secondly, like what @Slaw mentioned, you are potentially blocking on JavaFX Application thread, depending on your actual implementation (your example isn't really a JavaFX application).
Next, ExecutorService has 2 main overloads for submit().
The first overload takes in a Callable. This overload allows you to retrieve the value returned by the Callable (by calling get() on the returned Future), because Callable refers to something that is can be called - it can return value.
The second overload takes in a Runnable. Since Task implements Future RunnableFuture interface, and Future RunnableFuture interface extends Runnable interface, passing in a Task would be equivalent to calling this overload. This overload does not expect a result to be returned, because Runnable is something that you run without a result. Calling get() on the Future returned by this overload will block until the task finishes, and null will be returned. If you need to retrieve the value returned by the Task, you need to call get() of the Task, not the Future returned by ExecutorService.submit().
Edit based on OP's comments
Firstly, since the calling method is already running in a background thread, and all tasks are expected to run sequentially (instead of parallelly), then you should just run them without all these additional ExecutorService and Task, unless there is another reason why this has to be done.
Secondly, a List object is nothing but an object doing referencing. What could have really affected performance is that you are copying the reference of the elements to the new list. You could have used List.subList()if the indices are known, as the returned list would use the same backing array as the original list, so there isn't an additional O(n) operation for copying.
Comment for this answer: my semaphore is there to make sure I create each sublist just before I'm ready to run a new thread. in my actual application the list is much bigger and submitting them would take a lot of memory and choke the CPU.
Comment for this answer: Also in my application I run the executor on another background daemon thread, so it won't freeze my GUI. This is just a test code.
Comment for this answer: "_Since `Task` implements `Future` interface, and `Future` interface extends `Runnable` interface..._". `Future` does not extend `Runnable`. I believe you're thinking of `RunnableFuture` (which `Task` does implement through extending `FutureTask`).

Here is another answer: Task extends java.util.concurrent.FutureTask which in turn implements the Future interface. This means you can use a Task just like a Future.
Executor executor = ...;
Task<?&gt; task = ...;
executor.execute(task);
task.get(); // Future method
This will cause the thread calling get() to wait until completion. However, a Task's purpose is to communicate the progress of a background process with the JavaFX Application Thread. It's close relationship to the GUI means you will most likely be launching a Task from the FX thread. This will lead to get() being called on the FX thread which is not what you want as it will freeze the GUI until get() returns; you might as well have just called Task.run directly.
Instead, you should be using the asynchronous functionality provided by Task. If you want to retrieve the value when the Task completes successfully you can use the onSucceeded property or listen to the value/state property. There's also ways to listen for failure/cancellation.
Executor executor = ...;
Task<?&gt; task = ...;
task.setOnSucceeded(event -&gt; handleResult(task.getValue()));
task.setOnFailed(event -&gt; handleException(task.getException()));
executor.execute(task);
If you don't need the functionality provided by Task then it would probably be best to simply use Runnable or Callable directly.

{'source': 'StackExchangeDataset', 'subset': 'stackoverflow.com', 'metadata': {'AnswerCount': 2, 'CommentCount': 3, 'ContentLicense': 'CC BY-SA 4.0', 'CreationDate': '2018:00:08/13/18', 'FavoriteCount': None, 'PostTypeId': 1, 'Tags': '<java><multithreading><javafx>', 'Title': 'JavaFX Task Callable', 'ViewCount': 1140, 'id': 51830500, 'user_AboutMe': '<p>Java Developer</p>\n\n<p>Gamer</p>\n\n<p>Part-time programmer</p>\n\n<p>Full-time geek</p>\n', 'user_AccountId': 3765857.0, 'user_DisplayName': 'Ali', 'user_Reputation': 117.0, 'user_Views': 12.0, 'user_id': 3129429.0}}