Spring做为一个IOC/DI容器,帮助咱们管理了许许多多的“bean”。但其实,Spring并无保证这些对象的线程安全,须要由开发者本身编写解决线程安全问题的代码。web
Spring对每一个bean提供了一个scope属性来表示该bean的做用域。它是bean的生命周期。例如,一个scope为singleton的bean,在第一次被注入时,会建立为一个单例对象,该对象会一直被复用到应用结束。数据库
咱们交由Spring管理的大多数对象其实都是一些无状态的对象,这种不会由于多线程而致使状态被破坏的对象很适合Spring的默认scope,每一个单例的无状态对象都是线程安全的(也能够说只要是无状态的对象,无论单例多例都是线程安全的,不过单例毕竟节省了不断建立对象与GC的开销)。安全
无状态的对象便是自身没有状态的对象,天然也就不会由于多个线程的交替调度而破坏自身状态致使线程安全问题。无状态对象包括咱们常常使用的DO、DTO、VO这些只做为数据的实体模型的贫血对象,还有Service、DAO和Controller,这些对象并无本身的状态,它们只是用来执行某些操做的。例如,每一个DAO提供的函数都只是对数据库的CRUD,并且每一个数据库Connection都做为函数的局部变量(局部变量是在用户栈中的,并且用户栈自己就是线程私有的内存区域,因此不存在线程安全问题),用完即关(或交还给链接池)。websocket
有人可能会认为,我使用request做用域不就能够避免每一个请求之间的安全问题了吗?这是彻底错误的,由于Controller默认是单例的,一个HTTP请求是会被多个线程执行的,这就又回到了线程的安全问题。固然,你也能够把Controller的scope改为prototype,实际上Struts2就是这么作的,但有一点要注意,Spring MVC对请求的拦截粒度是基于每一个方法的,而Struts2是基于每一个类的,因此把Controller设为多例将会频繁的建立与回收对象,严重影响到了性能。session
经过阅读上文其实已经说的很清楚了,Spring根本就没有对bean的多线程安全问题作出任何保证与措施。对于每一个bean的线程安全问题,根本缘由是每一个bean自身的设计。不要在bean中声明任何有状态的实例变量或类变量,若是必须如此,那么就使用ThreadLocal把变量变为线程私有的,若是bean的实例变量或类变量须要在多个线程之间共享,那么就只能使用synchronized、lock、CAS等这些实现线程同步的方法了。
多线程