Spring单例bean与线程安全

  Spring容器中的bean默认是单例模式。当多个客户端同时请求一个服务时,容器会给每一个请求分配一个线程。这些线程会并发执行该请求对应的业务处理逻辑(成员方法),如果该处理逻辑中有对该单例bean状态的修改(体现为该单例bean的成员属性),则需要考虑线程同步问题。
  S pring使用ThreadLocal解决线程安全问题。一般情况下,只有无状态的Bean才可以在多线程环境下共享。Spring对一些Bean(如RequestContextHolder、TransactionSynchronizationManager、LocaleContextHolder等)中“非线程安全状态”,采用ThreadLocal进行处理,让它们也成为线程安全的状态,因此有状态的Bean也可以在多线程中共享了。
  ThreadLocal和线程同步机制( synchronized)都可以解决多线程中“相同变量”的访问冲突问题。
  线程同步机制 synchronized) 通过“对象锁”, 保证同一时间只有一个线程访问变量, 让不同的线程排队访问。 这时该变量是多个线程共享的,使用同步机制要求程序慎密地分析什么时候对变量进行读写,什么时候需要锁定某个对象,什么时候释放对象锁等繁杂的问题,程序设计和编写难度相对较大。
  ThreadLocal会为每一个线程提供一个独立的“变量副本”,从而隔离了多个线程对数据的访问冲突。因为每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了。ThreadLocal提供了线程安全的共享对象,在编写多线程代码时,可以把不安全的变量封装进ThreadLocal。

  如果某一进程中有多个线程在同时运行,而这些线程又同时运行某段代码。假如每次运行结果和单线程运行的结果是一样的,而且其他变量的值也和预期的是一样的,就是线程安全的。如果一个类所提供的方法,对于线程来说是原子操作,或者多个线程之间的切换不会导致该接口的执行结果存在二义性,那么便不用考虑同步的问题。
  线程安全问题都是由全局变量及静态变量引起的。 若每个线程中对全局变量、静态变量只有读操作,而无写操作,这个全局变量是线程安全的。若有多个线程同时执行写操作,则需要考虑线程同步,否则就可能影响线程安全。
  ① 常量始终是线程安全的,因为只存在读操作。
  ② 每次调用方法前都新建一个实例是线程安全的,因为不会访问共享的资源。
  ③ 局部变量是线程安全的。因为每执行一个方法,都会在独立的空间创建局部变量,它不是共享的资源。局部变量包括方法的参数变量和方法内变量。
  有状态就是有数据存储功能。有状态对象(Stateful Bean),就是有实例变量的对象,可以保存数据,是非线程安全的。在不同方法调用间不保留任何状态。
  无状态就是一次操作,不能保存数据。无状态对象(Stateless Bean),就是没有实例变量的对象,不能保存数据,是不变类,是线程安全的。

你可能感兴趣的:(spring)