美文网首页
Spring线程安全问题

Spring线程安全问题

作者: 西谷haul | 来源:发表于2021-11-06 10:35 被阅读0次

    1、两个概念

    有状态的bean:

    对象中有实例变量(成员变量),可以保存数据,是非线程安全的。

    无状态的bean:

    对象中没有实例变量(成员变量),不能保存数据,可以在多线程环境下共享,是线程安全的。

    2、spring的线程安全问题

    spring中的bean默认都是单例的,ioc容器中一个类只会存在一个实例对象。

    一般不会出现线程安全问题。在spring中,绝大部分bean都是无状态的,因此即使这些bean默认是单例的,也不会出现线程安全问题的。比如controller、service、dao这些类,这些类里面通常不会含有成员变量,因此它们被设计成单例的。如果这些类中定义了实例变量,就线程不安全了,所以尽量避免定义实例变量。

    对于spring中有状态的bean,比如RequestContextHolder、TransactionSynchronizationManager、LocaleContextHolder,为什么也能够设计成单例的呢?它是怎么保证线程安全的?

    Dao会操作数据库Connection,Connection是带有状态的,比如说数据库事务,Spring的事务管理器使用Threadlocal为不同线程维护了一套独立的connection副本,保证线程之间不会互相影响(Spring是如何保证事务获取同一个Connection的)。对于有状态的bean,spring采用ThreadLocal进行处理,使它们成为线程安全可以共享的对象。也可以使用原型模式(prototype),每次使用时都会重新生成一个对象,解决了线程不安全的问题。不要在bean中声明任何有状态的实例变量或类变量,如果必须如此,那么就使用ThreadLocal把变量变为线程私有的,如果bean的实例变量或类变量需要在多个线程之间共享,那么就只能使用synchronized、lock、CAS等这些实现线程同步的方法了。

    ps:无状态的Bean适合使用不变模式,即单例模式,这样可以共享实例,提高性能。有状态的Bean,多线程环境下不安全,适合使用Prototype原型模式。改变bean的作用域 把 “singleton”改为“protopyte” ,这样每次请求Bean就相当于是 new Bean() 这样就可以保证线程的安全了。

    springboot中修改作用域示意图
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    
    

    Prototype: 每次对bean的请求都会创建一个新的bean实例。

    相关文章

      网友评论

          本文标题:Spring线程安全问题

          本文链接:https://www.haomeiwen.com/subject/ucxjzltx.html