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

 

posted @ 2018-07-06 11:46  双子家的咸蛋蛋  阅读(1418)  评论(0编辑  收藏  举报