Java servlet是否可以安全地生成线程以满足请求? [英] Is it safe for a Java servlet to spawn threads in order to satisfy a request?

查看:124
本文介绍了Java servlet是否可以安全地生成线程以满足请求?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的Java(Tomcat 8)Web服务器是否可以安全地生成线程以响应HTTP请求?我看到帖子和论坛,有些人说它是绝对正常,其他人说不要这么做

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 others say 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容器是否存在任何其他潜在问题?

When I say safe, I mean is there anything inherently dangerous about what I'm proposing with regards to the stability of the web server. As @Burrman points out, a thread pool is good idea here, and I will do that. If I am using a thread pool, is there then any other potential issues with the servlet container that I should be concerned about or need to address?

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

I suppose what I'm thinking about is, for example, JDBC connections. I believe it's recommended to set that up using JNDI resource etc. and configuring that with Tomcat config. Is anything like that necessary or recommended for spawning arbitrary threads like in my example?

推荐答案

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

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.

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

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.

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

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. 使用 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
}


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

  • 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.

    一个简单的例子是:

    @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();
       }
    }
    


  • 这篇关于Java servlet是否可以安全地生成线程以满足请求?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆