• 并发编程日记-线程不安全的危害


    计数器

    @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统计的是正确的了。

  • 相关阅读:
    websocket1
    webpack 入门三
    weboack 入门二
    webpack 入门一
    输入一个url发生了什么
    http详解
    JavaScript对象详解
    javaScript垃圾回收机制
    js数据类型与隐式类型转换
    iOS证书申请、AppStore上架流程
  • 原文地址:https://www.cnblogs.com/maitian2013/p/14510011.html
Copyright © 2020-2023  润新知