Http://www.cnblogs.com/aheizi/p/5659030.html 1-Introduction
Asynchronous support in Servlet 3 provides the possibility of processing HTTP requests in another thread. This is particularly interesting when there is a long-running task, because when another thread processes the request, the container thread is freed and can continue to serve other requests.
This topic has been explained many times, and the classes provided by the Spring framework for this feature seem a bit confusing-returning callable and Deferredresult in a controller.
In this article, I will implement these two examples to show the differences.
All examples shown here include executing a controller that will perform a long-running task and then return the results to the client. Long-running tasks are handled by Taskservice:
@ServicePublicclass taskserviceimpl implements Span class= "Hljs-title" >taskservice {private final Logger Logger = Loggerfactory.getlogger (this.getclass ()); @Override public String execute () {try {thread.sleep (5000); Logger.info ( "Slow task executed"); return "Task finished";} catch (interruptedexception e) {throw new runtimeexception ();} }}
This web application was created with spring boot, and we will execute the following class to run our example:
@SpringBootApplicationpublic class MainApp { public static void main(String[] args) { SpringApplication.run(MainApp.class, args); }}
2-Blocked Controller
In this example, a request arrives at the controller. The servlet thread is not freed until a long-running method is executed and we exit @requestmapping
the comment method.
@RestControllerPublicClassBlockingcontroller {PrivateFinal Logger Logger = Loggerfactory.getlogger (This.getclass ());private final taskservice taskservice; @Autowired public blockingcontroller (Taskservice taskservice) { This.taskservice = Taskservice; } @RequestMapping (value = "/block", method = Requestmethod.get, produces = "text/html") public String executeslowtask () {Logger.info ( "Request received"); String result = Taskservice.execute (); Logger.info ( "Servlet thread released"); return result;}}
If we run this example Http://localhost:8080/block, in the log we will find that the servlet request will not be released until the long task is finished (5 seconds later).
2015-07-12 12: 41: 11.849[Nio-8080-exec-6]X. s. Web. controller. Blockingcontroller:Requestreceived2015-07-12 12: 41: 16.851[Nio-8080-exec-6]x. Spring. Web. Service. Taskserviceimpl: Slow task executed2015-07-12::16.851 [nio-8080-exec-6] x . s. Web. Controller. Blockingcontroller: Servlet thread released
3-Return callable
In this example, instead of returning the result directly, we will return a callable:
@RestControllerPublicClassAsynccallablecontroller {PrivateFinal Logger Logger = Loggerfactory.getlogger (This.getclass ());Privatefinal taskservice taskservice; @Autowired public asynccallablecontroller (Taskservice Taskservice) { this.taskservice = Taskservice;} @RequestMapping (value = "/callable", method = Requestmethod.get, produces = "text/html") public callable<string> executeslowtask () {Logger.info ( "Request received"); callable<string> callable = Taskservice::execute; Logger.info ( "Servlet thread released"); return callable;}
Returning callable means that spring MVC will invoke a task that performs the definition in a different thread. Spring will use Taskexecutor to manage threads. The servlet thread will be freed before waiting for a long-term task to complete.
2015-07-12 13: 07: 07.012[Nio-8080-exec-5]X. s. W. C. Asynccallablecontroller:Requestreceived2015-07-12 13: 07: 07.013[Nio-8080-exec-5]x.s.w.cservlet thread released2015-07-12 13 :07:12.014 [MvcAsync2] x .spring.web .serviceslow task executed
You can see that we have returned from the servlet before the long-running task has finished executing. This does not mean that the client has received a response. Communication with the client is still an open waiting result, but the received request for the thread has been freed and can serve the request of another customer.
4-Return Deferredresult
First, we need to create a Deferredresult object. This object will be returned by the controller. We will complete and callable the same thing when we release the servlet thread while another thread is working on a long-running task.
@RestControllerPublicClassAsyncdeferredcontroller {PrivateFinal Logger Logger = Loggerfactory.getlogger (This.getclass ());PrivateFinal Taskservice Taskservice;@AutowiredPublicasyncdeferredcontroller (Taskservice TaskService) {this.taskservice = Taskservice; } @RequestMapping (value = "/deferred", method = Requestmethod.get, produces = "text/html") public deferredresult<string> executeslowtask () {Logger.info ( Span class= "hljs-string" > "Request received"); deferredresult<string> Deferredresult = new deferredresult<> (); Completablefuture.supplyasync (Taskservice::execute). Whencompleteasync ((result, throwable) Deferredresult.setresult (result)); Logger.info ( "Servlet thread released"); return Deferredresult;}
So, what's the difference between returning Deferredresult and returning to callable? The difference is that this time the thread is managed by us. It is up to us to create a thread and set the result to Deferredresult.
Create an asynchronous task with Completablefuture. This will create a new thread where our long running tasks will be executed. That is, in this thread, we will set the result to Deferredresult and return.
In which thread pool are we retrieving this new thread? By default, the Supplyasync method in Completablefuture will run the task in the Forkjoin pool. If you want to use a different thread pool, you can pass a executor to the Supplyasync method:
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor)
If we run this example, we will get the following result:
2015-07-12 13: 28: 08.433[IO-8080-EXEC-10]X. s. W. C. Asyncdeferredcontroller:Requestreceived2015-07-12 13: 28: 08.475[IO-8080-EXEC-10]x. s. W. C. Asyncdeferredcontroller: Servlet thread released2015-07-12:13.469 [ ONPOOL-WORKER-1] x. Spring. Web. Service. Taskserviceimpl: Slow task executed
5-Conclusion
Standing at a certain altitude, callable and deferredresult do the same thing-releasing the container thread and running the long task asynchronously on another thread. The difference is who manages the threads that perform the task.
The code involved in this article spring-rest
"Turn" to understand callable and Spring Deferredresult