4. 单例模式线程安全问题--是否加锁

是否加锁问题指什么?

  1. 如果程序当中存在多线程,我们需要考虑当多个线程同时访问同一个内存空间时出现的问题,如果不加以控制,可能会导致数据出错,我们一般称这种问题为多线程并发问题,指多线程对共享数据的并发访问和操作。
  2. 而一般解决该问题的方式,就是通过C#中的lock关键字进行加锁,我们需要考虑我们的单例模式对象们是否需要加锁(lock)
  3. lock 的原理保证了在任何时刻只有一个线程能够执行被锁保护的代码块,从而防止多个线程同时访问或修改共享资源,确保线程安全

解决多线程并发来带的问题

继承MonoBehaviour的单例模式

可加可不加,但是建议不加。

  1. 因为Unity中的机制是,Unity主线程中处理的一些对象(如GameObject、Transform等等)是不允许被其他多线程修改访问的,会直接报错
  2. 因此我们一般不会通过多线程去访问继承MonoBehaviour的相关对象,所以就不会发生多线程并发问题

不继承MonoBehaviour的单例模式

  1. 基类添加锁
    在这里插入图片描述
  2. 子类也可以用锁
    在这里插入图片描述
  3. 优化
    在这里插入图片描述
/// <summary>
/// 单例模式基类,主要目的是避免代码的冗余,方便实现单例模式的类
/// </summary>
/// <typeparam name="T"></typeparam>
//where约束T必须是class,还有有一个公共的无参构造函数
public abstract class BaseManager<T> where T : class/*,new()*/
{
    public static T instance;

    // 用于加锁的对象
    protected static readonly object lockObj = new object();

    // 属性的方式
    public static T Instance
    {
        get
        {
            if (instance == null)
            {
                lock (lockObj)
                {
                    // 两次判断空是必要的,当第一个线程拿了钥匙进来后,第二个线程在等待,第一个线程实例化单例对象之后,第二个线程如果没有判断空,就会再new一个单例对象
                    if (instance == null)
                    {
                        //instance = new T();

                        // 利用反射得到无参私有的构造函数,来用于对象的实例化
                        Type type = typeof(T);
                        //  BindingFlags.Instance | BindingFlags.NonPublic, //表示成员私有方法
                        //    null,                                         //表示没有绑定对象
                        //    Type.EmptyTypes,                              //表示没有参数
                        //    null);                                        //表示没有参数修饰符
                        ConstructorInfo info = type.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, Type.EmptyTypes, null);

                        if (info != null)
                        {
                            instance = info.Invoke(null) as T;
                        }
                        else
                        {
                            Debug.LogError("没有得到对应的无参构造函数");
                        }
                    }


                }
            }
            
            return instance;
        }
    }

   
}

总结

  1. 项目需要用到多线程才需要加锁,根据需求而定
  2. 继承MonoBehaviour的单例模式不加锁
  3. 不继承MonoBehaviour的单例模式根据项目是否用到多线程判断加不加锁
在Spring中,Bean的默认作用域是单例模式,即每个容器只会创建一个实。对于单例模式的Bean,如果多个线程同时访问该Bean的方法或属性,可能会引发线程安全问题。这是因为多个线程共享同一个实,对实的修改可能会相互干扰。因此,需要特别注意在单例模式下处理线程安全问题。 对于解决单例模式下的线程安全问题,可以采取以下几种方式: 1. 方法级别加锁:在需要保证线程安全的方法上使用synchronized关键字,确保同一时间只能有一个线程访问该方法。这种方式简直接,但会降低并发性能。 2. 使用ThreadLocal:ThreadLocal是Java提供的一种线程级别的变量隔离机制。可以将需要共享的对象存储在ThreadLocal中,每个线程都拥有自己的副本,避免了线程安全问题。可以将非线程安全的对象存储在ThreadLocal中,确保每个线程都使用自己的对象副本。 3. 将Bean的作用域设置为prototype:使用prototype作用域的Bean在每次被注入或获取时都会创建一个新的实,解决了单例模式下的线程安全问题。可以通过在Bean的配置文件中设置scope属性为"prototype"来实现。 总结起来,为了解决Spring Bean单例模式下的线程安全问题,可以采用方法级别加锁、使用ThreadLocal或将Bean的作用域设置为prototype等方式来保证线程安全性。具体选择哪种方式需要根据实际场景和需求来决定。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值