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

后端 未结 5 1028
后悔当初
后悔当初 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:08

    JEE server stores some information in thread local variables. E.g. security context for JAAS, JTA transaction, ... New plain java thread has no access to such information. AsyncContext and JEE ExecuterService are integrated into server and can transparently spread request state to managed threads.

    0 讨论(0)
  • 2020-12-11 10:09

    Also, besides excellent answer of kuporific I really advise you to think if your result computation could be expressed in terms of map / filter / group operations on lists or maps, because in 90% of cases it's possible to do so.

    And if that's the case I would really advise you to use Java 8 Stream.parallelStream functionality as outlined in this official tutorial

    Please ask separate question if you are interested if/how it's possible to express your computation in that way

    Also, answering your initial question - it's perfectly fine to spawn threads to parallelise your computation anywhere (including servlets), however I would really advise to measure performance before and after optimization mainly because of reasons described in this superb article

    0 讨论(0)
  • 2020-12-11 10:17

    In my opinion

    1. this idea has not sense if thread should give effect in same request (cit. in order to satisfy a request)
    2. may have sense (if done properly) when effect of thread (running / ended) will be visible in next requests (especially via AJAX). Most servlet frameworks have way how to do "in orthodox way" long operations.

    To be clear: this is not normal way to do typical everyday AJAX tasks (must divide design to "main" request and next children ajax requests, using your framework), but AJAX can present state of background long thread.

    In my conception Thread or equivalent can be started from few/rare request, far below limits etc, but if it is done from every request, it is very bad design.

    0 讨论(0)
  • 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<Result1> f1 = executor.submit(new Callable<Result1>() {
            @Override
             public Result1 call() throws Exception {
                // do expensive stuff here.
                return result;
            }
         });
      
         Future<Result2> f2 = executor.submit(new Callable<Result2>() {
            @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();
         }
      }
      
    0 讨论(0)
  • 2020-12-11 10:35

    In principle, yes. But you have to keep an eye on the total number of threads you are spawning to make sure you're not using too many resources.

    Using a thread pool can help keep your number of threads under control.

    0 讨论(0)
提交回复
热议问题