Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to analyze FutureTask Source Code in Java Asynchronous programming

2025-02-23 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Servers >

Share

Shulou(Shulou.com)06/01 Report--

This article is to share with you about how to analyze FutureTask source code in Java asynchronous programming. The editor thinks it is very practical, so I share it with you. I hope you can get something after reading this article.

Asynchronous programming of Java is a very commonly used multithreading technology.

However, the previous tasks mainly tended to thread pooling and did not talk about asynchronous programming.

Everything starts from the example, we first through the example Demo to have an intuitive impression, and then in-depth understanding of the concept and principle.

Use the example

It is easy to use.

Running result:

Task 1 asynchronous execution: 0 task 2 asynchronous execution: 0 task 2 asynchronous execution: 1. Task 2 asynchronous execution: 45 synchronous code task 2 asynchronous execution: 24. Task 1 async execution: 199 Task 1: execution complete. Task 2 asynchronously executed: 199 Task 2: execution completed

If you execute this program many times, you will find that the results are very different, because the two tasks and synchronous code are executed asynchronously by multiple threads, and the printed results are of course random.

Looking back on what this Demo did.

Build a thread pool

Throw two tasks into the thread pool that need to be performed

Finally, get the results of these two tasks.

The second point is to execute two tasks asynchronously, the two tasks and the main thread are executed concurrently with three threads, and the third point is to wait for the results of the two tasks synchronously in the main thread.

It's easy to see that the advantage of asynchronous programming is that it allows unrelated tasks to execute asynchronously without blocking the main thread. If the main thread needs the result of asynchronous execution, waiting for the result at this time will be more efficient and improve the execution efficiency of the program.

Let's take a look at the implementation principle of the whole process.

Source code analysis

Generally in the actual project, there will be configured with their own thread pool, it is recommended that when using asynchronous programming, configure a dedicated thread pool, do a good job of thread isolation, so as to avoid asynchronous threads affecting the work of other modules. For convenience in Demo, call the Exectors method directly to generate a temporary thread pool, which is not recommended on a daily basis.

Let's start with this ExecutorService.submit () method and look at the overall implementation.

ExecutorService.submit () defines an interface. This interface takes a Callable parameter (the task performed) and returns a Future (calculation result).

Callable is the equivalent of a task that needs to be performed. It does not take any parameters, it can return results, and it can throw exceptions. Similarly, there is Runnable, which also does not receive, except that it does not return results or throw exceptions, which need to be handled within the task. To sum up, Callable is more like a method call, while Runnable is a call that doesn't care about the result. After JDK 8, they can all be written with Lamda expressions instead of inner classes (see Demo for details).

Future, the result of an asynchronous calculation. The corresponding calculation result can be obtained by calling the get () method. If the calculation is not done asynchronously when the call is made, it will block waiting for the calculation result. It also provides a way to try to cancel the execution of a task.

Looking back at the implementation of ExecutorService.submit (), the code is in the implementation class AbstractExecutorService.

In addition to the implementation of its interface, two variants are provided. The original interface only receives Callable parameters, and the implementation class has also been added to receive Runnable parameters.

If you read the previous "do you really understand ThreadPoolExecutor thread pool technology?" You will have a new understanding after reading the source code. You should understand that ThreadPoolExecutor can call the execute () method to perform tasks. The submit () method adds an extra layer of FutureTask to the Callable/Runnable so that the execution results have a place to store and also adds a function that can be canceled. The original execute () can only perform tasks and will not return results. The specific implementation principle can be analyzed in the previous article.

FutureTask is the implementation of RunnableFuture. RunnableFuture inherits the Future and Runnable interfaces and defines the run () interface.

Because FutureTask has a run () interface, you can create a FutureTask to execute alone with a Callable/Runnable directly. But this has no asynchronous effect, because it does not enable a new thread to run, but blocks execution on the original thread.

It is clear here that the submit () method focuses on creating a FutureTask using Callable/Runnable, and then multithreading executes the run () method to achieve the effect of asynchronous processing and getting the result. FutureTask focuses on how the run () method holds and saves the results of the calculation.

FutureTask.run ()

First determine the state state of the futureTask object, and if it is not NEW, prove that it has already started, and then exit execution. At the same time, the futureTask object assigns the current thread to the variable runner (which is the Thread type, indicating which thread the object uses to execute) through CAS, and exits if CAS fails.

In the outer try {} code block, the null and state status for callable must be NEW. The inner try {} code actually calls callable and starts executing the task. If the execution is successful, the ran variable is set to true, and the result is saved in the result variable, which proves that the run has passed successfully; if an exception is thrown, it is set to false,result, and the exception is saved by calling setException (). Finally, if ran is true, call set () to save the result result.

Take a look at the implementation of setException () and set ().

The basic process of the two is the same: CAS replaces the state and saves the result in the outcome variable channel, but the result type saved by setException () is always Throwable. Another difference is the final state state, one is EXCEPTION and the other is NORMAL.

Both methods end up calling finishCompletion (). This method is mainly to work with the thread pool to wake up the next task.

FutureTask.get ()

From the above run () method, the result of the final execution is placed in the outcome variable. So how to get the result out of it in the end, let's take a look at the get () method.

As you can see from the source code, the get () method takes two steps. The first step is to judge the state first, and if the calculation is complete, you need to block and wait for it to be completed. The second step, if completed, calls the report () method to get the result and return it.

Let's take a look at the awaitDone () blocking waiting for completion. The timeout function can be selected in this method.

In the spin for () cycle

First determine whether the thread is interrupted, if interrupted, throw an exception to exit.

Then start to determine the running state value, if state is greater than COMPLETING, it proves that the calculation is in the final state, and the final state variable is returned.

If state is equal to COMPLETING, it is proved that the calculation has started and is still being calculated. In order to avoid too much CPU time on the spin of the for loop, the program executes Thread.yield (), reducing the thread from running state to ready state, giving up CPU time.

If none of the above status is true, then state is NEW and execution has not started yet. Then the program will now add a WaitNode to the current loop and call LockSupport.park () in the next loop to block the current thread. When the run () method ends, the thread is woken up again to avoid spin consuming CPU time.

If you select the timeout feature and time out during blocking and spinning, the current timeout state is returned.

The report () method of the second step is relatively simple.

If the state is NORMAL and ends normally, the outcome variable is returned

If it is canceled or interrupted, a cancel exception is thrown

If it is EXCEPTION, throw outcome as an exception (the type previously saved by setException () is Throwable). As a result, an exception will be thrown throughout get ().

At this point, we have a relatively complete understanding of the principle of the Executor+Future framework, and FutureTask is the main implementation of the framework. Here is a summary of the key points

The Executor.sumbit () method performs a task asynchronously and returns a Future result.

The principle of submit () is to create a FutureTask object using Callable, and then execute the object's run () method to save the results in outcome.

When you call get () to get the outcome, if the task is not completed, it blocks the thread and waits for the execution to finish.

Both the exception and normal results are placed in outcome, and get () is called to get the result or throw an exception.

The above is how to analyze the FutureTask source code in Java asynchronous programming. The editor believes that there are some knowledge points that we may see or use in our daily work. I hope you can learn more from this article. For more details, please follow the industry information channel.

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Servers

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report