zoukankan      html  css  js  c++  java
  • 并发编程日记-线程不安全的危害

    计数器

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

  • 相关阅读:
    设计模式
    设计模式
    设计模式
    JS | Reduce
    JS | 数组的深拷贝与浅拷贝
    JS | 数组操作
    Lodash | 指定路径对Object操作
    Git | 场景总结
    ES6 Class
    SpringBoot | Jpa @Id @GeneratedValue
  • 原文地址:https://www.cnblogs.com/maitian2013/p/14510011.html
Copyright © 2011-2022 走看看