计数器
@WebServlet(name = "HelloServlet", urlPatterns = {"/hello"})
public class HelloServlet extends HttpServlet {
private static final Logger LOG = Logger.getLogger(HelloServlet.class.getName());
private Integer count = 0;
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
++count;
processRequest(request, response);
LOG.info(String.format("计数 %d", count));
}
}
按常理多少次请求后就会打印出计数多少。
ab -n300 -c20 http://localhost:8080/servlet-demo/hello
正常下,执行第一次 计数应为300
事实上得到的却不是
再执行..
2 ~ 590
3 ~ 879
4 ~ 1170
几乎没有规律,并不是预期的 300的倍数。
解释
实际上++count
是一个读取-修改-写入的操作。
假设线程A、B 同时读取到了值是m,同时写入+1后的值m+1。结果count = m+1,则事实上整个计数就少了1,应该为m+2。
处理
将count
声明为AtomicInter
private Integer count = 0;
private AtomicInteger atomicCount = new AtomicInteger(0);
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
++count;
processRequest(request, response);
LOG.info(String.format("计数count %d", count));
LOG.info(String.format("计数atomicCount %d", atomicCount.incrementAndGet()));
}
可以看到,AtomicInteger
统计的是正确的了。