zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    在ASP.NET Core中使用TagHelpers
    ASP.NET Core使用Redis
    ASP.NET Core MVC中视图
    HTTP状态码
    ASP.NET Core中静态文件
    ASP.NET Core中使用依赖注入
    在ASP.NET Core中使用多个环境
    ASP.NET Core读取配置文件
    HTML+CSS解决高度塌陷和垂直重叠
    Element-UI的表格合计行的列添加操作按钮
  • 原文地址:https://www.cnblogs.com/goujh/p/9272793.html
Copyright © 2011-2022 走看看