Servlet 和 Spring MVC 是不是线程安全的
太长不看:默认情况下 servlet
不是线程安全的;Spring bean
是否线程安全取决于这个 bean 的 scope。
Servlet 为什么不是线程安全的
单个 servlet 实例中的方法会被多个线程同时调用很多次,而 servlet 类中的变量是引用传递,多个线程同时存取某个变量时,就会产生线程安全问题。
以下方法可以让 servlet 或其中的一部分代码块变成线程安全的:
- 使用
syncronized
关键字。
1 | import java.io.*; |
- 使用
SingleThreadModel
类
如果在 Sun Java System Web Server 7.0
中部署单线程 servlet 时,servlet 引擎会创建一个 servlet 实例池,并保持内存中有多个 servlet 实例的副本。要想调整实例池中的实例数量,可以调整 Web Server 中的 singleThreadedServletPoolSize
属性。这种情况下,服务器的性能可能会降低,如果池中的所有实例全部被占用,那么新到来的请求就必须要在队列中等待某个实例被释放。
1 | import java.io.*; |
Spring Bean 什么时候是线程安全的,什么时候不是
首先,singleton
的 bean 不是线程安全的。在不使用 @Lazy
注解时,框架会在启动时就初始化好 singleton bean。但是框架不会管理开发人员怎么用这些 singleton bean,换言之,开发人员要自己处理线程安全问题。
而被 @RequestScope
注解标记的 bean 是线程安全的,因为这些 bean 不会在线程之间共享,而是在每次请求到来时都会创建新的实例。
Session scope 的 bean 也不是线程安全的,因为这些 bean 会与用户的会话绑定,每有一个新用户发来请求,就会创建一个新的 bean。但是,用户发来的请求可能是并行的,所以也有可能产生线程安全问题。
Prototype bean 是不是线程安全取决于它与哪种 bean 绑定。如果它是被一个 singleton bean 所依赖,因为 singleton bean 不是线程安全的,这个 prototype bean 也将被多个线程访问,所以此时 prototype bean 不是线程安全的;如果它被一个 request scope 的 bean 所依赖,那么这个 prototype bean 就是线程安全的,因为它会随着 request scoped bean 消亡而消亡,同时不会被多个线程共享。
除此之外,如果一个 bean 是无状态的,那么无论是什么 scope,它都是线程安全的。
参考文档
- Handling Threading Issues
- Spring bean thread safety guide