Thread pools can execute multiple tasks concurrently. Sometimes, we may want to track the execution results of tasks. Even within a certain period of time, if the task is not completed, we may also want to cancel the execution of tasks. In order to support this feature, ThreadPoolExecutor provides FutureTask for tracking the execution and cancellation of tasks. This article introduces the implementation principle of FutureTask.
In order to better understand the implementation principle of FutureTask, we first provide several important interfaces and class structures, as shown in the figure below:
ThreadPoolExecutor provides the submit interface for submitting tasks. Submit supports two different interfaces: Runnable and Callable. In order to provide a unified external interface, jdk internally wraps Runnable into a Callable, all of which is implemented through the RunnableAdapter adapter. The following is the source code of RunnableAdapter:
static final class RunnableAdapter<T> implements Callable<T> { final Runnable task; final T result; RunnableAdapter(Runnable task, T result) { this.task = task; this.result = result; } public T call() { task.run(); return result; } }RunnableAdapter is the implementation class of Callable, which implements the call method. The call method simply calls task.run() and then returns the result, which ensures that only the Callable interface needs to be handled uniformly internally.
Through the previous section, we know that the submitted Runnable task is internally converted to Callable tasks. Check the return value of the submit method, which is a Future. In fact, this Future is a FutureTask instance. Through this instance, calling the get method can block the current thread until the task is completed and the result is returned.
The entire call chain looks like this:
worker thread -> futureTask.run() -> callable.call() -> task.run()
If the Callable task is submitted, there are only the first three calls.
In order to better demonstrate the entire process, the following examples will be used to demonstrate the execution process.
1. Submit a Callable task to the thread pool (Runnable will also be converted to Callable). At this time, the Callable is passed into a FutureTask instance, as shown below:
2. The thread pool uses a thread to execute the FutureTask task.
The process of executing tasks is relatively simple. In the end, the Callable.call() or Runnable.run() method will be called, and a result will be obtained, which will store the result in the outcome property of the FutureTask instance, and the status will be modified to NORMAL, indicating that the task has been executed and the result can be obtained.
We assume that multiple threads call the get method of the same FutureTask instance during the execution of callable.call() . At this time, these threads will be blocked and stored in a stack, as shown in the figure below:
Threads 1, 2, and 3 call FutureTask.get method. Since the task has not been executed, all three threads will be blocked and sleepy. There is a stack in FutureTask to store waiting threads. The top pointer of the stack is referenced by FutureTask.waiters . When the task is executed, the threads in the entire stack will iterate. At this time, each thread will be awakened and the task execution result can be successfully obtained (the execution result is stored in FutureTask.outcome) .
FutureTask also supports the cancellation function of tasks, all of which coordinate multiple threads through the state of FutureTask.
The FutureTask interface is an implementation mechanism that provides us with tracking and controlling the execution of tasks. Compared with the thread pool itself, it is relatively simple and I believe it is not difficult to understand.
The above is all the content of this article about the implementation principle of FutureTask in Java thread pool. I hope it will be helpful to everyone. Interested friends can continue to refer to other related topics on this site. If there are any shortcomings, please leave a message to point it out. Thank you friends for your support for this site!