0

我有两个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”作为响应。

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

谢谢。

4

1 回答 1

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);
      }
    }
  }
}
于 2012-11-13T18:34:21.933 回答