Small knowledge, big challenge! This paper is participating in theEssentials for programmers”Creative activities.
Writing in the front
Today we are going to talk about the age-old problem of asynchrony and concurrency. Asynchrony is the most effective way to solve concurrency. Solve the time-consuming problem, so that the database query, RPC remote call and other time-consuming operations can be carried out at the same time, to achieve the purpose of rapid interface response, and effectively solve the concurrency problem.
Okay, without further ado, let’s get to the topic of the day. I don’t know if any of you have ever used DeferredResult
Today I’m going to talk to you about how to do asynchronous programming with DeferredResult, and you’re welcome to read an article I wrote earlier
Dry! SpringBoot uses listening events to implement asynchronous operations
Servlet
Out of DeferredResult. Let’s talk about servlets, which are familiar to everyone. Whether you’re using Struts2 or springMVC in your project, they’re essentially packaged servlets.
After servlet3.0 support for asynchrony, we use the following code for asynchrony:
// Test servlet asynchrony
//asyncSupported =true
@WebServlet(urlPatterns = "/testSyncServlet",asyncSupported =true)
public class WorkServlet extends HttpServlet{
private static final long serialVersionUID = 1L;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// Set ContentType to turn caching off
resp.setContentType("text/plain; charset=UTF-8");
resp.setHeader("Cache-Control"."private");
resp.setHeader("Pragma"."no-cache");
final PrintWriter writer= resp.getWriter();
writer.println("Servlet asynchrony");
writer.flush();
List<String> textArr=new ArrayList<String>();
for (int i = 0; i < 10; i++) {
textArr.add("zuoye"+i);;
}
// Enable asynchronous requests
final AsyncContext ac=req.startAsync();
doProcess(ac, textArr);
writer.println("Servlet asynchrony complete");
writer.flush();
}
private void doProcess(final AsyncContext ac, final List<String> textArr) {
ac.setTimeout(1*60*60*1000L);
ac.start(new Runnable() {
@Override
public void run(a) {
// Get the character output stream through response
try {
PrintWriter writer=ac.getResponse().getWriter();
for (String text:textArr) {
writer.println("\" "+text+"\" Request in process");
Thread.sleep(1*1000L);
writer.flush();
}
ac.complete();
} catch(Exception e) { e.printStackTrace(); }}}); }}Copy the code
The most important one above is AsyncContext ac=req.startAsync(); Enable asynchronous requests. SetTimeout Sets the timeout period. Ac. start Enables the thread to execute service requests.
Spring MVC’s asynchronous processing capabilities
As we all know, Spring MVC is designed around the Front ControllerPattern, where a central Servlet DispatcherServlet provides a shared routing algorithm for request processing and is responsible for routing requests.
Dispatcherservlets, like any Servlet, need to be declared and mapped according to the Servlet specification using Java configuration or WebXML. In turn, the DispatcherServlet uses Spring configuration to discover the delegate components needed for request mapping, view resolution, exception handling, and so on.
Spring MVC certainly has deep integration with the Servlet 3.0 asynchronous request handling described earlier:
-
DeferredResult and Callable serve as return values in the Controller method and provide basic support for a single asynchronous return value.
-
The controller can use the reaction client and return the reaction type for reaction processing.
Spring MVC internally puts the ServletRequest into asynchronous mode by calling Request.startAsync ()
Okay, so the whole point of this is to give you a head start on how DeferredResult works with springMvc and you’re using SpringBoot to run your projects, so I’m sure you’re not just looking at native servlets. Now let’s introduce our hero of the day
Asynchronous processing based on DeferredResult
As mentioned above, once asynchronous request handling is enabled in the Servlet container, the Controller method can wrap any supported method return values using DeferredResult.
1.Create an instance of DeferredResult
DeferredResult<String> deferredResult = new DeferredResult<String>();
Copy the code
2,Set timeout, operation after completion
deferredResult.onTimeout(() -> {
log.info("Call timeout");
});
deferredResult.onCompletion(() -> {
log.info("Call completed");
});
Copy the code
3,Result of enabling thread setting
new Thread(() > {
try {
// Simulate time-consuming operations
TimeUnit.SECONDS.sleep(10);
// Returns the OK result
deferredResult.setResult("ok"}
catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
Copy the code
The complete code
// Define a thread pool first
private static ThreadPoolExecutor BIZ_POOL = new ThreadPoolExecutor(8.8.1, TimeUnit.SECONDS,new LinkedBlockingQueue<>(1),
new ThreadPoolExecutor.CallerRunsPolicy());
// Call the DeferredResult asynchronous mechanism
@PostMapping("/testSync")
DeferredResult<String> listPostDeferredResult(a){
DeferredResult<String> deferredResult = new DeferredResult<String>();
BIZ_POOL.execute(new Runnable() {
@Override
public void run(a) {
try {
Thread.sleep(3000);
deferredResult.setResult("ok");
}catch (Exception e){
e.printStackTrace();
deferredResult.setErrorResult("error"); }}});return deferredResult;
}
Copy the code
conclusion
In this code, we create a business thread pool BIZ_POOL, and then the Controller method creates a DeferredResult object in listPostDeferredResult. We then submit our request processing logic to the business thread pool BIZ_POOL, which sets the result to the created DeferredResult after its internal processing, and finally return the created DeferredResult object. The whole process is as follows:
-
When the Tomcat container receives a request with the path personDeferredResult, it assigns a container thread to execute the DispatcherServlet for the request dispatch. The request is assigned to the Controller with the Path personDeferredResult. We then execute the listPostDeferredResult method, which creates a DeferredResult object, submits the processing to the thread pool for processing, and returns the DeferredResult object.
-
In Spring MVC, when the personDeferredResult method returns, it saves the DeferredResult object to an in-memory queue or list, and then calls Request.startAsync () to enable asynchronous processing. Object and invoke DeferredResult setResultHandler method, set up after the asynchronous results to reroute the results of the callback function (logical) in WebAsyncManager startDeferredResultProcessing method
-
Finally, the asynchronous task executed in the business thread pool produces a result, which is set to the DeferredResult object, which is then called, and Spring MVC dispatches the request result back to the Servlet container to continue processing. The DispatcherServlet is called again and continues processing with the returned asynchronous results, eventually writing the response back to the requester.
OK, that’s all for today’s talk about DeferredResult. I’m going to talk about the source code and principles of DeferredResult later because I don’t have enough space. Follow me if you’re interested. Later we will study together
And Callable distinction
DeferredResult is similar to Callable in that it returns asynchronously, except that Callable can’t set the timeout directly and needs to work with FutureTask. DeferredResult allows you to set the timeout directly.
I wrote an article about Callable in the past. If you’re interested, check it out:
Dry! Concurrent programming — Future
overtones
Thank you for reading, if you feel that you have learned something, please like, follow. Also welcome to have a question we comment below exchange
Come on! See you next time!
To share with you a few I wrote in front of a few SAO operation
Talk about different strategy patterns (Bookmarks)
Copy object, this operation is a little SAO!