• SpringMVC成员变量并发状态下使用测试


    1.SpringMVC默认是单例的,使用成员变量在并发状态下该成员变量的值是被共享的

    测试平台   我们目前正在开发的电商项目  (架构组成SpringCloud + SpringBoot + Spring + SpringMVC + Mybatis)

    测试说明  构造两个并发访问的请求,它们都会使用一个成员变量,其中一个请求会执行一段耗时15秒左右的for循环的代码,另外一个请求不会执行这段代码,但会修改成员变量的值

    测试过程  第一个请求先访问,在执行for循环时紧接着第二个请求访问,第二个请求会马上执行完并且改变成员变量的值,最后看前面这个请求执行完15秒的for循环后再使用这个成员变量时,值有没有改变

    测试源码  

        

    @RestController
    @RequestMapping("/service")
    public class SurvivalGoldReceiveController extends BaseController {
    
    
        private String nowDate = new SimpleDateFormat("yyyy-MM-dd HH:MM:ss").format(new Date());
    
    
        @RequestMapping(value = "/toSurvivalGoldReceive")
        public ModelAndView toSurvivalGoldReceive(){
            HttpServletRequest request = this.getRequest();
            GeCustomer geCustomer = (GeCustomer)request.getSession().getAttribute(UserPersonalConstant.LOGIN_USER);
            logger.info("start--nowDate = " + geCustomer.getCustomeraccount() + nowDate);
            logger.info("其它请求进来后");
            if ("youyuqi02".equals(geCustomer.getCustomeraccount())) {
                StringBuilder sb = new StringBuilder();
                long startTime = System.currentTimeMillis();
                for (int i = 0; i < 100000000; i++) {
                    sb.append("测试SpringMVC中使用成员变量" + i);
                    sb.append("测试SpringMVC中使用成员变量" + i);
                    sb.append("测试SpringMVC中使用成员变量" + i);
                    sb.append("测试SpringMVC中使用成员变量" + i);
                    sb.append("测试SpringMVC中使用成员变量" + i);
                    sb.delete(0,sb.length());
                }
                long estimatedTime = System.currentTimeMillis() - startTime;
                logger.info("执行一亿次字符串的拼接与删除耗时 : " + String.valueOf(estimatedTime).substring(0,2) + "秒");  //1s=1000毫秒=1000000微秒=1000000000纳秒
            }else{
                nowDate = "成员变量被其它请求改变了";
            }
            logger.info("end--nowDate = " + geCustomer.getCustomeraccount() + nowDate);
            if(geCustomer == null){
                return go("/vipcenter/home");
            }else{
                return go("/vipcenter/survivalGoldReceive/survivalGoldReceiveList");
            }
        }
    }

    测试结果:第二个请求将成员变量nowDate的值改为了字符串“成员变量被其它请求改变了”,第一个请求再使用这个成员变量时,值已经发生了改变

    总结:SpringMVC在单例情况下发生并发时会修改成员变量的值,所以慎用成员变量

     

    2.设置controller为多例,@Scope("prototype")

    测试源码

    @RestController
    @Scope("prototype")
    @RequestMapping("/service")
    public class SurvivalGoldReceiveController extends BaseController {
    
    
        private String nowDate = new SimpleDateFormat("yyyy-MM-dd HH:MM:ss").format(new Date());
    
    
        @RequestMapping(value = "/toSurvivalGoldReceive")
        public ModelAndView toSurvivalGoldReceive(){
            HttpServletRequest request = this.getRequest();
            GeCustomer geCustomer = (GeCustomer)request.getSession().getAttribute(UserPersonalConstant.LOGIN_USER);
            logger.info("start--nowDate = " + geCustomer.getCustomeraccount() + nowDate);
            logger.info("其它请求进来后");
            if ("youyuqi02".equals(geCustomer.getCustomeraccount())) {
                StringBuilder sb = new StringBuilder();
                long startTime = System.currentTimeMillis();
                for (int i = 0; i < 100000000; i++) {
                    sb.append("测试SpringMVC中使用成员变量" + i);
                    sb.append("测试SpringMVC中使用成员变量" + i);
                    sb.append("测试SpringMVC中使用成员变量" + i);
                    sb.append("测试SpringMVC中使用成员变量" + i);
                    sb.append("测试SpringMVC中使用成员变量" + i);
                    sb.delete(0,sb.length());
                }
                long estimatedTime = System.currentTimeMillis() - startTime;
                logger.info("执行一亿次字符串的拼接与删除耗时 : " + String.valueOf(estimatedTime).substring(0,2) + "秒");  //1s=1000毫秒=1000000微秒=1000000000纳秒
            }else{
                nowDate = "成员变量被其它请求改变了";
            }
            logger.info("end--nowDate = " + geCustomer.getCustomeraccount() + nowDate);
            if(geCustomer==null){
                return go("/vipcenter/home");
            }else{
                return go("/vipcenter/survivalGoldReceive/survivalGoldReceiveList");
            }
        }
    }

    测试结果  第一个请求最后获取的成员变量的值并未改变

    总结 第二种是多例的,每次访问会创建一个Controller对象,属于线程安全的,但会过多的耗费内存,第一种是单例的,只会创建一次对象,在并发情况下会修改成员变量的值,但会节省内存空间,所以,老司机都用第一种,但会有意识的避免使用成员变量。

    参考文献 springMVC 谨慎使用成员变量https://blog.csdn.net/panda_in5/article/details/78528762

  • 相关阅读:
    转载__Java内部类
    Fragment之介绍(转)
    转载__Android-屏幕适配需要注意的地方
    转载__广播机制
    Activity的启动模式--总结
    图片_ _Android--加载大分辨率图片到内存
    转载—— android 瀑布流的实现详解,附源码
    转载_安卓性能优化
    C# Byte[] 数组操作
    C# 测算代码运行时间 Stopwatch
  • 原文地址:https://www.cnblogs.com/goujh/p/9272793.html
Copyright © 2020-2023  润新知