一、可见性
    直接感受下吧!直接上代码。

    1. @Controller
    2. @RequestMapping("/factory")
    3. public class MachineFactoryController {
    4. // 静态变量位于堆内存中,所有线程共享
    5. private static int i = 0;
    6. @RequestMapping("/access")
    7. @ResponseBody
    8. public Long access(@RequestParam(name = "provinceId") Long provinceId, @RequestParam(name = "cityId") Long cityId) {
    9. int loopCount = 10;
    10. for (int j = 0; j < loopCount; j++) {
    11. // 模拟其他业务
    12. }
    13. i = i + 1;
    14. int step = 10;
    15. if (i % step == 0) {
    16. LOGGER.info("{}", i);
    17. }
    18. return cityId;
    19. }
    20. @RequestMapping("/monitor")
    21. @ResponseBody
    22. public Integer monitor() {
    23. LOGGER.info("{}", i);
    24. return Integer.valueOf(i);
    25. }
    26. }

    第一步,启动jmeter开启一个线程组,共有100个线程。使用这个线程组发起100次/factory/access请求,理论上,只要这100个线程执行完毕,i的最终结果是100。但实际上,并不是。
    machine_factory_access.jpg
    第二步,使用谷歌浏览器直接访问/factory/monitor,打印堆内存中变量i的值,神奇的事情发生了,可以发现是98,这是问什么?

    第三步,思考造成i最终结果不正确的原因是什么?
    多线程环境下,每个线程同时访问共享资源时,一定存在线程可见性问题。

    第四步,如何解决可见性问题?
    其实,就此场景而言,使用volatile虽然解决了可见行问题,但是解决不了非原子操作的问题。有两种解决方案。
    a、对共享资源加锁,比如说synchronize。
    b、使用线程安全的类型,比如说AtomicInteger类。