Java servlet是否可以安全地生成线程以满足请求?

我的Java(Tomcat 8)Web服务器是否可以安全地生成线程以响应HTTP请求?我看到帖子和论坛有些人说它是absolutely fine,其他人说not to do it.

我的用例是这样的:

 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    ...
    ...
    final MyResult res = new MyResult();
    Thread first = new Thread(new Runnable() {
         @Override
         public void run() {
             // put this into res
         }
     });
     Thread second = new Thread(new Runnable() {
         @Override
         public void run() {
             // put that into res
         }
     });
     first.start();
     second.start();
     first.join(10000);
     second.join(10000);

     // return res
 }

当我说安全时,我的意思是关于Web服务器的稳定性,我提出的内容是否有任何本质上的危险.正如@Burrman指出的那样,线程池在这里是个好主意,我会这样做.如果我正在使用线程池,那么我应该关注或需要解决的servlet容器是否存在任何其他潜在问题?

我想我正在考虑的是,例如,JDBC连接.我相信建议使用JNDI资源等进行设置,并使用Tomcat配置进行配置.是否有必要或建议产生任意线程,如我的例子?

首先,它看起来你正在修改两个线程中的结果对象.这不是线程安全的,因为第一个和第二个线程可能彼此不可见或者servlet正在运行的线程可见.有关详细信息,请参阅this article.

其次,如果你在这些其他线程中修改响应,不,这将是不安全的.退出doGet方法后,您应该考虑发送的响应.在您的示例中,在这两个线程运行之前,响应将有可能被发送回客户端.

假设MyResult结果影响响应对象(您要么将结果添加到响应中,要么影响响应代码等).有几种方法可以解决这个问题.

>使用ExecutorService和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
}

>更高级的技术是Asynchronous Processing.如果您的请求需要很长时间来处理,则使用异步处理是一个好主意.它不会改善任何一个请求的延迟,但它确实允许Tomcat在任何给定的时间点处理更多请求.

一个简单的例子是:

@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();
   }
}
https://stackoverflow.com/questions/33568235/is-it-safe-for-a-java-servlet-to-spawn-threads-in-order-to-satisfy-a-request

本站文章除注明转载外,均为本站原创或编译
转载请明显位置注明出处:Java servlet是否可以安全地生成线程以满足请求?