ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

线程安全-Spring Bean 作用域类型(Scope)

2020-06-12 18:03:24  阅读:197  来源: 互联网

标签:变量 会话 作用域 Spring 安全 Bean 实例 线程 单例


  16:53:00 2020-06-12

  今天上课学习MyBatis时,在老师讲到SqlSession是线程不安全的时候,提到这样一句话:“SqlSession是单线程对象,因为它是非线程安全的,是持久化操作的独享对象,类似JDBC中的Connection,底层就封装了JDBC连接”。我当时就感到疑惑:因为我习惯从字面上去理解一个东西,Connection译为连接,连接之后再开启一个会话,这个会话是独享的我可以理解,而当他说Connection也是独享的时候我就犯懵了,后来想清楚了,JDBC中的Connection和SqlSession其实也就是一回事,如果我是JDBC驱动的设计人员,我就会把Connection改为Session。

  这几天一直是围绕着如何搭建一个Spring+SpringMVC+MyBatis框架的Web项目,对SpringMVC做了挺多的学习,也了解了一些基础的知识,这里,我就将看过的博客文章,自己觉得写得不错,结合自己的理解,翻新一遍,整合到自己的博客里来。


 

一. Spring Bean 的作用域类型

  1. Singleton 单例,默认作用域。
  2. Prototype 原型,每次创建一个新实例。
  3. Request 请求,每次 Http 请求创建一个新实例,适用于 WebApplication 环境下。
  4. Session 会话,同一个会话共享一个实例,不同会话使用不同的实例。
  5. Global-session 全局会话,所有会话共享一个实例。

二. Spring 单例模式及线程安全

  Spring 框架中的 Bean,或者说组件,获取实例的时候都是默认单例模式。

  单例模式的定义:确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。无状态的 Bean 适合用单例模式(无状态就是一次操作,不能保存数据,无状态对象就是没有实例变量的对象),这样可以共享实例,提高性能;有状态的 Bean ,多线程环境下不安全,适合用 Prototype 原型模式,每次对 Bean 的请求都会创建一个新的实例(有状态就是有数据存储功能,有状态对象就是有实例变量的对象,可以保存数据)。

 

三. 线程安全的问题

  当多个用户同时请求一个服务时,容器会给每一个请求分配一个线程,这时多个线程会并发执行该请求对应的业务逻辑(成员方法),此时就要注意,如果该处理逻辑中有对单例状态的修改(体现为改单例的成员属性),则必须考虑线程同步的问题。

  如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的,或者说:一个类或者程序所提供的接口对于线程来说是原子性操作或者多个线程之间的切换不会导致该接口的执行结果存在二义性,这样也叫做线程安全。

  说来说去,线程安全问题都是由全局变量及静态变量引起的。

  若每个线程中对全局变量、静态变量只有读操作,没有写操作,一般来说,这恶全局变量就是线程安全的;若多个线程同时执行写操作,一般都需要考虑线程同步,否则就可能影响线程安全。

  有三种情况是线程安全的(不限于此):

  1. 常量始终是线程安全的,因为只存在读操作。
  2. 每次调用方法前都新建一个实例是线程安全的,因为不会存在访问共享的资源。
  3. 局部变量是线程安全的,因为每执行一个方法,都会在各自的方法栈里头创建局部变量,它不是共享的资源,局部变量包括方法的参数变量和方法内声明的变量。

四. 线程安全的实现方式

  1. 在同步机制,通过对象的锁机制保证同一时间只有一个线程访问变量。这时该变量是多个线程共享,使用同步机制要求程序缜密地分析什么时候对变量进行读写,什么时候需要锁定某个对象,什么时候释放对象锁等繁杂的问题,程序设计的难度相对较大。

  2. ThreadLocal 从另一个角度来解决多线程的并发访问,ThreadLocal 会为每一个线程提供一个独立的变量副本,从而隔离了多个线程对数据的访问冲突,因为每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了,ThreadLocal 提供了线程安全的共享对象,在编写多线程代码时,可以把不安全的变量封装进 ThreadLocal。

  概括起来说,对于多线程资源共享的问题,同步机制采用了“以时间换空间”的方式,ThreadLocal 采用了“以空间换时间”方式,前者仅提供一个变量,让不同的线程排队访问,后者为每一个线程都提供了一个变量,因此可以同时访问而互不影响。


 

  线程安全案例

  SimpleDateFormat(下面简称 sdf)类内部有一个 Calendar 对象引用,它用来存储和这个 sdf 相关的日期信息,例如 sdf.parse(dateStr). sdf.format(date) 诸如此类的方法参数传入的日期信息相关的 String, Date 等等,都是交由 Calendar 引用来存储的,这样就会导致一个问题,如果你的 sdf 是静态的,那么多个 Thread 之间就会共享这个 sdf,同时共享这个 Calendar 引用,可见是非线程安全的,根据前面的状态的定义,这是一个有状态的对象。

  对策:

  1. 使用 synchronized 关键字进行数据同步,或者使用 ThreadLocal 保证线程安全。

  2. 不使用 JDK 自带的时间格式化类,使用其他替代:

    • 使用 Apache Commons 里的 FastDateFormat,宣称是又快又线程安全的 SimpleDateFormat,可惜它只能对日期进行格式化,不能对日期串进行解析。
    • 使用 Joda-Time 类库来处理时间相关问题,该类库对时间的处理方式比较完美。     

标签:变量,会话,作用域,Spring,安全,Bean,实例,线程,单例
来源: https://www.cnblogs.com/taiyo/p/13101042.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有