Servlet正在将数据写入另一个servlet的输出流

时间:2012-11-10 05:25:38

标签: apache servlets asynchronous tomcat7 anonymous-class

我有两个servlet,如下所示:

public class ServletA extends HttpServlet {
  public void doGet(final HttpServletRequest request, 
                    final HttpServletResponse response) {
    // Kick off some async processing
    RequestQueue.putRequest(new RequestInfo(...), new FutureCallback<ResponseInfo> () {
      @Override
      public void completed(ResponseInfo responseInfo) {
        // Send some data to database
        TransactionManager.getInstance().create(...);
      }
    )};
    // Send response to client
    response.getWriter().println("ServletA: SUCCESS");
  }
}

public class ServletB extends HttpServlet {
  public void doGet(final HttpServletRequest request, 
                    final HttpServletResponse response) {
    // Use a CountDownLatch to force synchronous processing on an asynchronous construct
    final CountDownLatch completedSignal = new CountDownLatch(1);
    RequestQueue.putRequest(new RequestInfo(...), new FutureCallback<ResponseInfo> () {
      @Override
      public void completed(ResponseInfo responseInfo) {
        // Send some data to database, and send response to client
        TransactionManager.getInstance().create(...);
        response.getWriter().println("ServletB: SUCCESS");
        completedSignal.countDown();
      }
    )};
    completedSignal.await();
  }
}

问题是,在负载很重的情况下,调用ServletA的客户端有时会收到“Servlet B:SUCCESS”作为响应。

为什么会这样?怎么修复?

感谢。

1 个答案:

答案 0 :(得分:1)

向ServletB添加AtomicBoolean以确保仅在修复问题后使用响应对象:

public class ServletB extends HttpServlet {
  public void doGet(final HttpServletRequest request, 
                    final HttpServletResponse response) {
    // Use a CountDownLatch to force synchronous processing on an asynchronous construct
    final CountDownLatch completedSignal = new CountDownLatch(1);
    // Use an AtomicBoolean to ensure response is only used once
    AtomicBoolean responseSent = new AtomicBoolean(false);
    RequestQueue.putRequest(new RequestInfo(...), new FutureCallback<ResponseInfo> () {
      @Override
      public void completed(ResponseInfo responseInfo) {
        // Ensure response has not already been sent
        if(!responseSent.compareAndSet(false, true)) { return; }
        // Send some data to database, and send response to client
        TransactionManager.getInstance().create(...);
        response.getWriter().println("ServletB: SUCCESS");
        completedSignal.countDown();
      }
    )};
    if(!completedSignal.await(60, TimeUnit.SECONDS)) {
      // Ensure response has not already been sent
      if(responseSent.compareAndSet(false, true)) {
        response.sendError(503);
      }
    }
  }
}