In general, there are 3 interfaces for the executors.
executorservice (extends the above)
scheduledexecutorservice (extends the above)
executorservice and scheduledexectutorservice are mostly used. executor is abstract.
1 Executor interfaces
It's not concretly used. It's abstract. Only one interface - execute().
User/Application can implement one's own executor by implementing this interface. But it's not wise to implement one's own and why not reuse JAVA has afforded?
Practical in daily work. It's with the feature to manage the lifecycle of both the tasks and the executor. By working with the Future, we can manage the task.
Use execute(), submit(). The submit accepts either the callable or the runnable.
We can shutdown() or shutdownnow() the executor service.
If we simply want to allocate and manage a threadpool for our application and assign tasks and get tasks executed immediately. This is perfect to match the needs.
Add the limited interfaces on top of the above. Typically, "schedulexxx". If we want to get the tasks to executed on a certain period or to be executed later (delay), this matches the need.
2 Executor implementation
We can implement our own executors by implementing the according interfaces. But in practice, it's cost saving by using what JAVA affords.
The 'Executors' supplies the factory methods to construct the executor for us. Kinds of executors can be constructed depending on what we need.
That's it for the exector service framework. Simply put, 3 interfaces and one facility to construct the executor for us.
Future is the interface. ScheduleFuture is its subinterface that extends it. FutureTask is a concrete class to implement Future.
When we submit a task to an executor, we get a Future to return. Future links, tracks the submitted task. Future is able to be used for task lifecycle managment, task query (cancel, done?, etc)
If we don't expect to call Future.get() to get the task result, simply declare Future<?> instead Feature<T> (T is the returned type of the Future.get)
When we submit a task to an executor, we get a Future to track this task. For example, ExcutorService returns a Future after calling its submit(). We don't care about the concrete class for this interface and the specific executor returns the instance and to us, just know it's an interface instance.
Solely used for the ScheduledExecutorService when we schedule() the task.
FutureTask - Can serve as both a 'Future' and a runnable or callable 'Task'.
It's a concrete class implementation for future and runnablefuture interfaces.
We can create a instance of FutureTask and submit to an executor. (construct the FutureTask instance with a runnable instance + result to return or with a callable instance). The FutureTask is more like a Task and let exectuor to execute for you.
In the meanwhile, it's also a Future. You can use it to manage the lifecycle of the submitted task (handle it the same as the Future returned by the .submit()).
The diff is, normally, we submit a task and we get a returned Future. The task & the Future are a pair and they are about the same task; While with the FutureTask, task & Future are now combined to the same instance and it's a task and it's also a Future for us to directly manipulate the task.
We can say the normal 'Future' is controlled by the executor. In fact, FutureTask is used more in the JAVA implementation for the concrete executors.
FutureTask is assigned to the executor via "execute()", while the normal callable or runnable can also be done via the submit(). Submit returns a Future.
I believe the Future and Task in JDK are linked closely together and they shall be one instance. JAVA constructs the FutureTask instance internally and return it to us the reference for us to use (to us, it's just a Future). Normally we just use the Future reference JDK returns to us (by submit()); if we use FutureTask, we don't need to get that reference, we have our own "Future"Task in our APP.
You would only need to use FutureTask if you want to change its behaviour or access its Callable later but a good reason to let the Executor construct the FutureTask for you is to ensure that there is no possible way more than one reference exists to the FutureTask instance. That is, the Executor owns this instance. Majority of times, we use Callable and Future
3.4 A lot more 'Future'...