Is it safe for a Java servlet to spawn threads in order to satisfy a request?

后端 未结 5 1067
后悔当初
后悔当初 2020-12-11 10:01

Is it safe for my Java (Tomcat 8) web server to spawn threads in response to a HTTP request? I\'m seeing posts and forums where some people say it\'s absolutely fine, and ot

5条回答
  •  孤城傲影
    2020-12-11 10:21

    First, it looks you're modifying the result object in both threads. This is not thread safe because what the first and second threads do might not be visible to each other or to the thread the servlet is running on. See this article for more info.

    Second, if you are modifying the response in these other threads, no, this will not be safe. Once you exit the doGet method, you should consider the response sent. In your example, there's a chance the response will get sent back to the client before those two threads have run.

    Suppose the MyResult result affects the response object (you're either adding the result to the response, it's affecting the response code, etc). There are a few ways to handle this.

    1. Use ExecutorService and Future:

      public void doGet(HttpServletRequest request, HttpServletResponse response) {
         // Creating a new ExecutorService for illustrative purposes.
         // As mentioned in comments, it is better to create a global 
         // instance of ExecutorService and use it in all servlets. 
         ExecutorService executor = Executors.newFixedThreadPool(2);
      
         Future f1 = executor.submit(new Callable() {
            @Override
             public Result1 call() throws Exception {
                // do expensive stuff here.
                return result;
            }
         });
      
         Future f2 = executor.submit(new Callable() {
            @Override
            public Result2 call() throws Exception {
               // do expensive stuff here.
               return result;
            }
         });
      
         // shutdown allows the executor to clean up its threads. 
         // Also prevents more Callables/Runnables from being submitted.
         executor.shutdown();
      
         // The call to .get() will block until the executor has
         // completed executing the Callable.
         Result1 r1 = f1.get();
         Result2 r2 = f2.get();
         MyResult result = new MyResult();
         // add r1 and r2 to result.
         // modify response based on result
      }
      
    2. A more advanced technique is Asynchronous Processing. Using async processing is a good idea if your requests take a long time to process. It does not improve the latency of any one request, but it does allow Tomcat to handle more requests at any given point in time.

      A simple example would be:

      @WebServlet(urlPatterns={"/asyncservlet"}, asyncSupported=true)
      // Rather than @WebServlet, you can also specify these parameters in web.xml    
      public class AsyncServlet extends HttpServlet {
         @Override
         public void doGet(HttpServletRequest request, HttpServletResponse response) {
            response.setContentType("text/html;charset=UTF-8");
            final AsyncContext acontext = request.startAsync();
            acontext.start(new Runnable() {
               public void run() {
                  // perform time consuming steps here.
                  acontext.complete();
         }
      }
      

提交回复
热议问题