我的编程空间,编程开发者的网络收藏夹
学习永远不晚

浅谈springboot如何保证多线程安全

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

浅谈springboot如何保证多线程安全

如何保证多线程安全

1.springboot在多线程并发访问下是怎么做的

我们在Controller下,一般都是@AutoWired一些Service,由于这些Service都交给了spring进行管理,因此他们单例的,对于在Controller中调用他们的方法,由于方法在JVM中属于栈操作,所以对于每一个线程来说,栈都是独立的,因此是线程安全的。

而由于Controller本身是单例模式 (非线程安全的), 这意味着每个request过来,系统都会用原有的instance去处理,这样导致了两个结果:一是我们不用每次创建Controller,二是减少了对象创建和垃圾收集的时间;由于只有一个Controller的instance,当多个线程调用它的时候,它里面的instance变量就不是线程安全的了,会发生窜数据的问题。

如果我们定义了一个全局的实例,如 private Company company = new Company(); 而在@RequestMapping方法中去用到了他, 这里就存在并发线程安全的问题。

对于所有的请求request,这个company对象是相通的。

当然我们也可以用这个特性来制作访问计数器 只需要定义一个private int cout = 0; 在每一次请求后cout++;

当然我并不推荐这么做,计数器最好用redis来操作。

总结以上问题,不要在Controller里出现类的实例。即便加了线程安全操作,也会出现性能问题。当然无论是Controller还是Service,如果你一定要使用对象的属性,如private Company company = new Company();可以加上ThreadLocal的引用,如private ThreadLocal<Company> tc = new ThreadLocal<>();但是把这种使用的对象放进方法中初始化(即进入JVM栈中更好)。

2.controller在多线程下如何尽可能保证线程安全,如何取舍

当多个请求对controller进行请求时,它的instance的单例模式是线程不安全的,因此我们如果要保证完全的线程安全,需要对于每次请求都创建一个新的controller实例,在spring中使用@RequestScope注解定义它的作用域为requst,即一次请求即为一个实例,这样就可以保证controller层面上的线程安全。但是这样做会有一个很大的缺点,就是这种方式当并发很大时,创建bean的新实例就比重用原有的controller实例要慢许多。

因此还有折中的办法,就是将@RequestScope设置为session级别的作用域,这样每当一次会话,spring就会创建一个controller实例,而不需要每次请求都去创建一次实例,大大提高了访问的速度,虽然这样无法保证绝对的线程安全,但是在大部分的业务逻辑上都有效的防止了线程安全的问题。

此外,spring的作用域还有singleton(单例,也是spring默认的作用域级别,即永远使用同一个实例)、prototype(原型)、globalSession(全局)

3.小结一下

Spring本身并没有解决并发访问的问题。如果bean的范围不是线程安全的(例如在controller上面的成员变量或者静态变量就是线程不安全的),但其方法包含一些您总是希望安全运行的关键代码或者使用了静态字段需要对其进行并发修改,请在该方法上使用synchronized关键字。或者使用一些有提供线程安全的集合进行相应的多线程操作。

单例模式与线程安全问题踩的坑

最近有客户反映,使用公司产品时,偶尔会存在崩溃情况,自己测试无问题,然后去查日志,是报空指针。于是顺藤摸瓜 往上找,好嘛,之前的开发使用了成员变量,感觉问题就是在这里了,因为众所周知,springboot 采用的是单例模式,所以,使用成员变量时一定要谨慎。

下面上一张该类的截图

大家可能看到了,该类上面加上了@Scope("prototype") 注解,该注解的作用是将该类变成多例模式。讲道理因为变为了多例,应该不会有线程问题了。

我先说下我这边的一个代码环境

上面大家看到的BaseController这个类里面有个init方法,会在继承它的类的所有方法前执行。

使用的是@ModelAttribute注解,这个注解的意思是,在该controller的所有方法前执行,意在初始化,我猜测之前的同事应该是为了获取相同的一些参数,抽调出来做一个父类,随着迭代,别的同事为了方便,拿来就用,导致很多controller继承了该类。

@Scope("prototype")注解:大家设想一下,若父类加了@Scope("prototype")注解,子类controller并没有加该注解,会怎样呢?该注解是否还有意义?再比如,我在某service上加上@Scope("prototype")注解,但调用的controller没有加@Scope("prototype")注解,那么会出现什么样的结果呢?大家可以去测试一下,测试方法也很简单,就是在对应的父类或service的无参构造方法里打印该类的地址。

下面说下我的测试结果

先说父类上加了@Scope("prototype")注解,子类上没有加这种情况。结果是,同一子类继承的为同一父类,不同子类继承为不同父类。理解一下,很简单,因为springboot为单例模式,所以子类为单例,那么只有一个子类,父类肯定是一样的。所以,不同线程过来使用的为同一变量,就会有问题。

同理:在service上标注@Scope("prototype")注解,那在同一个controller里,该service还是同一个,也就是说还是单例的,在不同的controller里 是不同的。测试方法同上。

现在说下解决方法

1、是在继承该controller的子类上都加上@Scope("prototype")注解。这样做的好处是简单。坏处也同样明显,因为是多例的,那么就会产生大量的实体类,占用大量内存,若是回收不及时,有可能会出现内存溢出。

2、是将变量私有化,比如使用线程变量,对变量加锁等,技术上会复杂一些,而且调试不太好调试。说不定那些地方就会出现问题,毕竟是老代码。

3、将该类转换为拦截器,将变量放入request里,用的时候取出来。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程网。

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

浅谈springboot如何保证多线程安全

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

springboot怎么保证多线程安全

小编给大家分享一下springboot怎么保证多线程安全,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!如何保证多线程安全1.springboot在多线程并发访问下是怎么做的我们在Controller下,一般都是@AutoW
2023-06-22

redis如何保证线程安全

Redis通过单线程模型、原子操作、内存保护、锁机制、内置保护、持久性、复制、Lua脚本和事务等策略,确保了多线程环境下的线程安全性,保证数据完整性和一致性,以及服务器稳定性。
redis如何保证线程安全
2024-04-11

java多线程怎么保证线程安全

Java中有多种方式可以保证线程安全,以下是一些常见的方法:1. 使用synchronized关键字:使用synchronized关键字可以将代码块或方法标记为同步的,只有一个线程能够进入同步块或方法执行,其他线程需要等待。这样可以确保同一
2023-09-13

详解SpringBoot是如何保证接口安全的

对于互联网来说,只要你系统的接口会暴露在外网,就避免不了接口安全问题。 如果你的接口在外网裸奔,只要让黑客知道接口的地址和参数就可以调用,那简直就是灾难。这篇文章主要介绍了SpringBoot保证接口安全的方法,需要的可以参考一下
2023-02-02

如何保证小程序的安全性

要保证小程序的安全性,可以采取以下措施:使用合法的开发工具和平台:确保使用官方或可信赖的开发工具和平台进行小程序开发,避免使用未经授权或不可信赖的工具。加强用户身份验证:采用多因素身份验证等方式,确保用户身份的真实性和安全性。加密数据传输:
如何保证小程序的安全性
2024-04-17

Go语言atomic.Value如何不加锁保证数据线程安全?

这篇文章主要介绍了Go语言atomic.Value如何不加锁保证数据线程安全详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2023-05-20

python多线程的线程如何安全实现

1、引言 当前随着计算机硬件的快速发展,个人电脑上的 CPU 也是多核的,现在普遍的 CUP 核数都是 4 核或者 8 核的。因此,在编写程序时,需要为了提高效率,充分发挥硬件的能力,则需要编写并行的程序。Java 语言作为互联网应用的主要
2022-06-02

Java多线程编程安全如何退出线程

小编给大家分享一下Java多线程编程安全如何退出线程,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!线程停止Thread提供了一个stop()方法,但是stop()
2023-05-30

Java对象的内存分配过程是如何保证线程安全的

本篇内容介绍了“Java对象的内存分配过程是如何保证线程安全的”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!在开始进入正题之前,请允许我问一
2023-06-16

Win XP远程控制时如何保证安全

跟其他远程控制技术类似,远程协助和远程桌面同样要在使用前考虑好安全问题。对于最高级别的安全要求,根本不建议在实际应用中使用远程控制技术,不过要明白这种技术也能给用户带来便利。本章会就使用远程控制技术时保证安全性的方法进行说明。  远程协助 
2023-05-24

Python中如何实现一个线程安全的并发缓存对象,保证读写一致性和数据安全性

Python中如何实现一个线程安全的并发缓存对象,保证读写一致性和数据安全性在多线程的环境下,对共享数据进行读写操作需要考虑到线程安全的问题。当多个线程同时对一个缓存对象进行读写操作时,可能会导致数据不一致或者数据丢失的问题。为了解决这个问
2023-10-22

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录