java全局变量引起的并发问题「建议收藏」

java全局变量引起的并发问题「建议收藏」最近刚完成了一个短彩信群发平台的开发工作,系统采用springmvc+hibernate+jdbctemplate+mysql架构。其中遇见许多问题,闲暇之余记录下来以避免在后续项目中再犯同样的错误。先看下面小段代码,一个controller,一个service。       controller.java代码:    ……..    @Autowired

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

最近刚完成了一个短彩信群发平台的开发工作,系统采用springmvc+hibernate+jdbctemplate+mysql架构。其中遇见许多问题,闲暇之余记录下来以避免在后续项目中再犯同样的错误。

先看下面小段代码,一个controller,一个service。

       controller.java代码:
    ……..
    @Autowired
     private XXXService xxxService;
    ……..
    @RequestMapping(“/doXXX.do”)
    public void doXXX(){

        …..
        xxxService.saveXXX(String content,….);
        …..
    }
    XXXService.java代码:
    private String content;
    ……
    private void init(){//清空请求参数
        content = null;
        ……
    }
    public boolean saveXXX(String content, ……){

        this.init(content, …);
        this.content = content;
        //业务逻辑处理
    }

    以上这段代码在访问量不构成并发时不会出现什么问题。 但当一个请求还未完成,另一个请求已经开始执行的情况下就会出现问题(并发): 第二个请求执行执行init()方法会将第一个请求的content变量设置为null或它本身的值,这样数据就被篡改了。

    编码者这样写的目的是因为content等变量需要在多个方法中使用,而且变量很多,但又不想通过方法参数的方式来传递,故使用成员变量。

    先看看为什么会出现这种情况。 由于系统采用springmvc框架,springmvc核心控制器DispatcherServlet 默认为每个controller生成单一实例来处理所有用户请求,所以在这个单一实例的controller中,它的XXXService也是一个实例处理所有请求, 这样XXXService的成员变量就被所有请求共享。这样就会出现并发请求时变量内容被篡改的问题。

    那么出现这种问题如何解决呢? 
    第一种方式: 既然是全局变量惹的祸,那就将全局变量都编程局部变量,通过方法参数来传递。
    第二种方式: jdk提供了java.lang.ThreadLocal,它为多线程并发提供了新思路。 (当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本
         那么在什么地方使用ThreadLocal呢? 什么变量是请求公用的就将该变量托付给ThreadLocal来管理其线程副本, 所以我们在xxxService中使用它。
        XXXService.java代码:
        private ThreadLocal<String> contentTL = new ThreadLocal<String>();
        //private String content;使用contentTL代替content;
        ……
        public boolean saveXXX(String content, ……){

            this.contentTL.set(content);  

            //业务逻辑处理
            //在各方法中使用content时候用this.contentTL.get()代替
    }  

     此类并发篡改数据的问题,可以在开发工具中设置断点调试的方式来模拟并发。即第一次请求运行到断点时,查看content内容,并且不让程序继续往下运行,同时再发起一个请求,查看content内容。 如内容是第一次请求的内容,并且让第一个请求跑完后,第二个请求到断线处的content正确时,可以确定不会出现并发问题。

     如果有spring配置文件那就直接加上scope=”prototype”就行啦

原文地址:http://my.oschina.net/robolin/blog/78395

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/171746.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • mac 安装配置android sdk[通俗易懂]

    mac 安装配置android sdk[通俗易懂]一、安装sdk在mac上可以使用brew包管理工具来安装软件,所以要安装sdk,首先需要安装brew包,详情可参照我上一篇博客,这里就不过多赘述。1、安装好brew后,通过以下命令进行sdk的安装brewinstallandroid-sdk2、查看是否已安装成功,在终端执行:android二、配置sdk1、查看sdk安装路径brewlistandroid-sdk可见,我的sdk的安装路径是在/opt/homebrew/Caskroom/android.

    2022年7月21日
    63
  • .net断点续传的原理

    在了解HTTP断点续传的原理之前,先来说说HTTP协议,HTTP协议是一种基于tcp的简单协议,分为请求和回复两种。请求协议是由客户机(浏览器)向服务器(WEBSERVER)提交请求时发送报文的协议

    2021年12月26日
    41
  • 一种导致AbstractMethodError问题的原因

    一种导致AbstractMethodError问题的原因1)App和B-lib依赖于A-lib的不同版本,并且都实现了A-lib中定义的一个接口IFunc,运行时A-lib会调用各IFunc实现;2)B-lib仅在编译阶段依赖A-lib,实际运行的是APP中集成的A-lib;3)APP端升级了A-lib,在IFunc中新增了一个方法aNewMethod()。由于B-lib并未针对v2版本的A-lib进行适配,因此运行时当A-lib调用B-l…

    2022年5月5日
    65
  • setUp()和tearDown()函数

    setUp()和tearDown()函数

    2022年4月2日
    90
  • Java8 stream 之groupingBy() 分组排序

    Java8 stream 之groupingBy() 分组排序ListmatchsList=newArrayList();Map&amp;gt;MatchsListMap=matchsList.stream().collect(Collectors.groupingBy(Matchs::getMatchDate));此时MatchsListMap的排序规则是根据MatchDate降序的(默认),也就是说ma

    2022年8月20日
    50
  • 二级指针动态数组,模拟指针数组

    二级指针动态数组,模拟指针数组

    2021年8月18日
    61

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号