Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does Future require to perform the computation in a separate thread?

From the documentation

Future represents the result of an asynchronous computation.

Does it mean that a thread calling the method Future#get should not be a thread which performed the computation? So, is it appropriate if the thread calling Future#get start the computation if it has not been yet? I'm not sure If I can call it asynchronous computation...

like image 448
St.Antario Avatar asked Oct 01 '15 06:10

St.Antario


1 Answers

The term “asynchronous computation” does not mandate that the computation has to run in a different thread. If the API designers intended that, they had written “computation that runs in a different thread”. Here, it simply means that there is no specification about when the computation happens.

Likewise, the existing implementations provided by the JRE do not enforce a computation in a different thread. The probably most known implementation, FutureTask can be used as follows:

Callable<String> action = new Callable<String>() {
    public String call() {
        return "hello "+Thread.currentThread();
    }
};

FutureTask<String> ft=new FutureTask<>(action);
ft.run();
System.out.println(ft.get());

Normally, instances of FutureTask are created by an ExecutorService which will determine when and by which thread the computation will be executed:

ExecutorService runInPlace=new AbstractExecutorService() {
    public void execute(Runnable command) {
        command.run();
    }
    public void shutdown() {}
    public List<Runnable> shutdownNow() { return Collections.emptyList(); }
    public boolean isShutdown() { return false; }
    public boolean isTerminated() { return false; }
    public boolean awaitTermination(long timeout, TimeUnit unit) { return false; }
};
Future<String> f=runInPlace.submit(action);
System.out.println(ft.get());

Note that this execute() implementation does not violate its contract:

Executes the given command at some time in the future. The command may execute in a new thread, in a pooled thread, or in the calling thread, at the discretion of the Executor implementation.

Note the “or in the calling thread”…

Another implementation is the ForkJoinTask:

ForkJoinTask<String> fjt=new RecursiveTask<String>() {
    protected String compute() {
        return "hello "+Thread.currentThread();
    }
};
fjt.invoke();
System.out.println(fjt.get());

Note that, while this kind of task is intended to support splitting into subtasks, which can be executed by different threads, utilizing the calling thread is intentional here. If the task can’t be split, it runs entirely in the caller’s thread as that’s the most efficient solution.


These examples are all running in the caller thread, but none of them will execute the tasks within the get() method. In principle, that would not violate the contract as it returns the result value, when the computation has been performed, however, you are likely to have trouble when trying to implement the get(long timeout, TimeUnit unit) correctly. In contrast, having a non-working cancel() would be still within the contract.

like image 111
Holger Avatar answered Nov 09 '22 13:11

Holger