controller、service、Dao是否是线程安全的?

我有个朋友最近面试被问到controller、service、Dao是否线程安全问题,只知道说线程安全的,因为平时写代码就没考虑过,那可不行,这道题起码得吹个十多分钟。

线程安全的定义

当多个线程同时访问一个对象时,调用这个对象的行为都可以获得正确的结果,那这个对象便是线程安全的。

反过来说导致多线程环境下线程不安全的条件是对共享数据的操作是非原子的

对于Java类来说就是存在对象属性的并且对属性的修改是非原子的那么就是非线程安全的

如何保证线程安全

解决线程安全问题自然是破坏线程不安全产生的条件。

  • 不使用共享数据
    例如在Java中,如果一个类没有属性的,或者属性都是只读的,那么就是线程安全的,因为不存在共享数据。当然也可以使用线程本地变量Threadlocal使得变量是线程本地的,这样多线程访问Threadlocal变量相当于访问自己本地的变量不存在冲突的。

  • 确保操作共享数据是原子的
    常见方法就是让线程排队执行不要同时去修改,即通过同步机制实现即加锁。比如通过悲观锁synchronized、lock等, 或者乐观锁CAS等。

在Java中,基于JVM的线程模型,多线程对于一个变量的操作会先操作自己的本地内存里面的值,而且本地变量不会立马刷新到主内存,所以可能会导致其他线程无法及时获取到变量的最新值的情况。

而且由于处理器会对执行的指令进行重排优化,导致执行的顺序和我们代码写的不一样,比如我们的代码先执行一些准备工作,完成后使用一个变量标志准备完成,之后由于指令重排导致先执行了变量标志准备完成赋值,导致其他线程以为工作准备完成了就开始执行业务代码,但是实际上没完成准备,所以就会出现问题。

一般在对共享数据做同步时都会使用volatile配合使用,因为volatile能保证可见性和有序性避免上述问题的发生。

controller、service、dao类线程安全分析

通过上述条件判断controller、service类是否是线程安全的,
首先controller、service、Dao类默认情况下是单例的,因为spring bean在默认情况下的作用域是singleton的也就是单例的,所以系统只会初始化一次,每次请求的都是同一个实例,那么久有可能存在线程安全问题了,因为存在多线程同时访问一个是对象实例的情况。

所以要讨论是否线程安全的还得分情况来分析

如果controller、service、Dao类是无状态的,也就是说没有修改属性操作的,那么就是线程安全的,平时写MVC项目的时候一般controller、service、Dao类是无状态所以没有线程安全问题。

如果controller、service、Dao类的对属性的修改都增加同步机制了或者属性都是使用本地变量threadlocal那么也没有线程安全问题。

如果把bean的作用域设置成prototype模式那么也不存在线程安全问题,因为每次请求都生成新的对象,就相当于不存在多线程同时访问了。

singleton:单例,默认作用域。
prototype:原型,每次创建一个新对象。
request:请求,每次Http请求创建一个新对象,适用于WebApplicationContext环境下。
session:会话,同一个会话共享一个实例,不同会话使用不同的实例。
global-session:全局会话,所有会话共享一个实例。

结论

默认配置下Spring mvc 的 Controller、Service、Dao等bean都是单例的。意思就是系统只会初始化一次,所以每次请求的都是同一个实例在处理。所以说是否线程安全的还需要看开发者是如何处理的,

如果这个Bean,是一个无状态Bean或者如果成员变量的修改都做了相应的同步机制或者使用本地变量threadlocal等那么就是线程安全的。否则就不是线程安全的。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值