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

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

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

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • TP框架自带的正则验证的规则

    TP框架自带的正则验证的规则

  • vuejs 和 element 搭建的一个后台管理界面

    vuejs 和 element 搭建的一个后台管理界面

    2021年10月11日
  • Python数组切片_python print数组

    Python数组切片_python print数组文章目录numpy数组切片操作一维数组1、一个参数:a[i]2、两个参数:b=a[i:j]3、三个参数:格式b=a[i:j:s]二维数组numpy数组切片操作通过冒号分隔切片参数start:stop:step来进行切片操作:一维数组importnumpyasnpa=[1,2,3.4,5]print(a)[12345]1、一个参数:a[i]如[2],将…

  • Linux挂载磁盘分区「建议收藏」

    Linux挂载磁盘分区「建议收藏」Linux系统一般都会有未挂载的磁盘,如果我们想使用这些为挂载的磁盘就需要挂载到指定目录才能使用。一、有多个磁盘,将未分区的磁盘挂载1、进入root用户su–2、查看已挂载磁盘的使用情况:df–h可以看到系统已经挂载了sda磁盘,并分为sda1、sda2、sda3,3个分区3、查看所有磁盘信息(包括未挂载磁盘):fdisk–l4、创建新的磁盘…

  • mysql中kill掉所有锁表的进程

    mysql中kill掉所有锁表的进程很多时候由于异常或程序错误会导致个别进程占用大量系统资源,需要结束这些进程,通常可以使用以下命令Kill进程:mysql中kill掉所有锁表的进程2009-05-1214:03转载请保留如下作者信息作者:jesse博客:http://hi.baidu.com/leechl3点钟刚睡下,4点多,同事打电话告诉我用户数据库挂

  • 图像匹配方法浅谈_浅谈数学思想方法

    图像匹配方法浅谈_浅谈数学思想方法每次都想找个权威的图像匹配的综述看看。但看的论文零零散散,每家都说自己方法如何如何的好,其实我都半信半疑的,希望中国的研究学者能够脚踏实地的务实的多做点实事,牛顿说我成功是因为站在巨人的肩上。我是菜鸟

发表回复

您的电子邮箱地址不会被公开。

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