Spring的作用域
- singleton(单例):默认的scope,每个scope属性来表示该bean的作用域,是bean的声明周期。作用域为单例表示bean在第一次被注入时会创建一个单例对象,改对象会一直被复用到应用结束
- prototype(多例):bean被定义为在每次注入时都会创建一个新的对象
- request:bean被定义为在每个http请求中创建一个单例对象,也就是说在单个请求中都会复用这一个单例对象
- session:bean被定义为在一个session的生命周期内创建一个单例对象
- application:bean被定义为在servletContext的生命周期中复用一个单例对象
- websocket:bean被定义为在websocket的生命周期中复用一个单例对象
无状态对象
- 由Spring管理得大多数对象其实都是一些无状态的对象,这些对象不会因为多线程而导致状态破坏很适合Spring的默认scope.每个单例的无状态对象都是好线程安全的,换言之,只要是无状态的对象,不管是单例还是多例,都是线程安全的,只不过单例节省了不断常见对象和GC的开销。
- 无状态的对象包括常用的DO,DTO,VO等只是作为数据的实体模型的对象,还有Service,DAO,Controller这些没有自己的状态,只是用来执行某些操作。
Bean的安全使用
Spring对于bean的多线程安全问题没有任何保证与措施,对于每个bean的线程安全问题,根本原因在于对每个bean自身的设计,不要在bean中声明任何有状态的实例变量或类变量,如果必须设置,那么可以使用ThreadLocal把变量变为线程私有,如果bean的实例变量或类变量需要在多个线程之间共享,那么需要使用syncronized,lock,CAS等实现线程同步
ThreadLocal的使用
- ThreadLocal思想就是为线程提供一个线程私有的变量副本,这个多个线程可以所以修改自己线程局部的变量,不会影响其他线程。ThreadLocal含有一个ThreadLocalMap的内部类,该类采取线性探测法实现HashMap,它的key值r为ThreadLocal对象并采用软引用的方式来存储变量副本
- ThreadLocal提供的是浅拷贝,如果需要解决内部状态被改变的问题,可以通过重写其内部的initialValue()方法来实现深拷贝
- ThreadLocal与锁机制不一样的地方在于,锁更强调的是如何同步多个线程去正确共享一个变量,ThreadLocal则是为了解决同一个变量如何不被多个线程共享。从性能开销的角度来看,如果锁机制是时间换空间,那threadlocal就是空间换时间
- 为了安全使用ThreadLocal,必须像每次使用完锁就解锁一样,在每次使用ThreadLocal后都要调用remove()来清理无效的Entry