java之路--单例 Bean 的线程安全问题

文章讨论了在Spring中,单例Bean可能存在的线程安全问题,特别是对于有状态的Bean。解决方案包括避免使用可变成员变量,利用ThreadLocal为每个线程提供独立副本,以及将Bean的作用域改为原型。ThreadLocal提供了一种线程安全的共享对象方式,避免了传统同步机制的复杂性。


大部分 Bean 实际都是无状态(没有实例变量)的(比如 Dao、Service),这种情况下, Bean 是线程安全的。

因为Spring 默认情况下是单例的(singleton)。所有我们会遇见多个线程操作同一个对象的时候是存在资源竞争的问题。

常见的有两种解决办法:

1. 在 Bean 中尽量避免定义可变的成员变量。

2. 在类中定义一个 ThreadLocal 成员变量,将需要的可变成员变量保存在 ThreadLocal 中(推荐的一种方式)。

在同步机制中,通过对象的锁机制保证同一时间只有一个线程访问变量。这时该变量是多个线程共享的,使用同步机制要求程序慎密地分析什么时候对变量进行读写,什么时候需要锁定某个对象,什么时候释放对象锁等繁杂的问题,程序设计和编写难度相对较大。
  而ThreadLocal则从另一个角度来解决多线程的并发访问。ThreadLocal会为每一个线程提供一个独立的变量副本,从而隔离了多个线程对数据的访问冲突。因为每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了。不同线程只操作自己线程的副本变量。
  
ThreadLocal提供了线程安全的共享对象,在编写多线程代码时,可以把不安全的变量封装进ThreadLocal。

ThreadLocal代码举例

 private  static ThreadLocal<Integer> content=new ThreadLocal<Integer>(){
 
         protected  Integer initalValue(){
                return (int)(Math.random()*10+100);
            }
 
    };
 
    private  static ThreadLocal<Integer> test=new ThreadLocal<Integer>(){
 
        protected String initalValue(){
            return "单例模式是不安全的" +(int)(Math.random()*10+100);
        }
    };
public Object get(){
        System.out.println(content.get());
        System.out.println(test.get());
        System.out.println();
        return  test.get();
    }
  1. 将有状态的bean的作用域由“singleton”改为“prototype”。( 如注解 : @Scope(“prototype”) );
  2. 使用线程同步,加关键字synchronized。对多线程性能有一定影响(此方法没试验过 慎用!);
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值