Spring的Bean是线程安全的么?

Spring的Bean是线程安全的么?

一、概述

Spring容器本身并没有提供Bean的线程安全策略,所以可以说Spring容器中的Bean本身不具备线程安全的特性,但是具体情况还是要结合Bean的作用域来讨论。

二、Bean的作用域

  1. singleton:默认作用域,单例bean,每个容器中只有一个bean的实例。
  2. prototype:为每一个bean请求创建一个实例。
  3. request:为每一个request请求创建一个实例,在请求完成以后,bean会失效并被垃圾回收器回收。
  4. session:与request范围类似,同一个session会话共享一个实例,不同会话使用不同的实例。
  5. application:bean定义在servletContext的生命周期中复用一个单例对象(跨容器)。
  6. global-session:全局作用域,所有会话共享一个实例。如果想要声明让所有会话共享的存储变量的话,那么这全局变量需要存储在global-session中。

三、Bean的线程安全分析

  • 对于prototype作用域的Bean,每次都创建一个新对象,也就是线程之间不存在Bean共享,因此不会有线程安全问题。
  • 对于singleton作用域的Bean,所有的线程都共享一个单例实例的Bean,因此是存在线程安全问题的。

但是如果单例Bean是一个无状态Bean,也就是线程中的操作不会对Bean的成员执行查询以外的操作,那么这个单例Bean是线程安全的。解释一下:

  • 无状态Bean(Stateless Bean):就是没有实例变量的对象,不能保存数据,是不变类,是线程安全的。
  • 有状态Bean(Stateful Bean) :就是有实例变量的对象,可以保存数据,是非线程安全的。

对于有状态的bean(比如Model和View),就需要自行保证线程安全, 解决办法就是:

  • 将有状态的bean的作用域由“singleton”改为“prototype”
  • 采用ThreadLocal解决线程安全问题,为每个线程提供一个独立的变量副本

线程同步机制和ThreadLocal都是为了解决多线程中相同变量的访问冲突问题:

  • 同步机制采用了“时间换空间”的方式,仅提供一份变量,不同的线程在访问前需要获取锁,没获得锁的线程则需要排队。
  • ThreadLocal采用了“空间换时间”的方式。ThreadLocal会为每一个线程提供一个独立的变量副本,从而隔离了多个线程对数据的访问冲突。

版权声明:本文为qq_35958391原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。