You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何创建线程安全的单例静态实例?(ChaosEngine类场景)

线程安全全局单例ChaosEngine实现方案

要实现全局共享且线程安全的ChaosEngine单例,需要解决两个核心问题:保证单例实例唯一且线程安全地初始化,保证实例内部状态的访问和修改是线程同步的。以下是两种可行的实现方案:

方案一:双重检查锁定(Double-Check Locking)

通过双重检查锁定保证单例仅初始化一次,同时使用内部锁保护所有状态操作:

public class ChaosEngine {
    // 内部状态字段
    private int _Seed;
    private int _INext;
    private int _INextP;
    private int[] _SeedArray;

    // 单例初始化锁(保证实例仅创建一次)
    private static readonly object _singletonLock = new object();
    private static ChaosEngine _shared;

    // 内部状态锁(保护所有状态的读写操作)
    private readonly object _stateLock = new object();

    public int Seed { 
        get { lock(_stateLock) return _Seed; } 
        set { lock(_stateLock) Reseed(value); } 
    }

    // 私有构造函数,禁止外部实例化
    private ChaosEngine() {
        Reseed(Environment.TickCount);
    }

    public static ChaosEngine Shared {
        get {
            // 第一次检查,避免不必要的锁
            if (_shared == null) {
                lock(_singletonLock) {
                    // 第二次检查,保证仅初始化一次
                    if (_shared == null) {
                        _shared = new ChaosEngine();
                    }
                }
            }
            return _shared;
        }
    }

    private void Reseed(int seed) {
        lock(_stateLock) {
            _Seed = seed;
            // 以下是原ChaosEngine的SeedArray初始化逻辑(参考Random类实现)
            _SeedArray = new int[56];
            int num = (seed == int.MinValue) ? int.MaxValue : Math.Abs(seed);
            int num2 = 161803398 - num;
            _SeedArray[55] = num2;
            int num3 = 1;
            for (int i = 1; i < 55; i++) {
                int num4 = 21 * i % 55;
                _SeedArray[num4] = num3;
                num3 = num2 - num3;
                if (num3 < 0) num3 += int.MaxValue;
                num2 = _SeedArray[num4];
            }
            for (int j = 1; j < 5; j++) {
                for (int k = 1; k < 56; k++) {
                    _SeedArray[k] -= _SeedArray[1 + (k + 30) % 55];
                    if (_SeedArray[k] < 0) _SeedArray[k] += int.MaxValue;
                }
            }
            _INext = 0;
            _INextP = 21;
        }
    }

    // 示例随机数生成方法,必须加锁保证状态同步
    public int Next() {
        lock(_stateLock) {
            if (++_INext >= 56) _INext = 1;
            if (++_INextP >= 56) _INextP = 1;
            int num = _SeedArray[_INext] - _SeedArray[_INextP];
            if (num < 0) num += int.MaxValue;
            _SeedArray[_INext] = num;
            return num;
        }
    }
}

方案二:使用Lazy(推荐)

.NET的Lazy<T>类型默认支持线程安全的延迟初始化,无需手动写双重检查锁,代码更简洁可靠:

public class ChaosEngine {
    // 内部状态字段
    private int _Seed;
    private int _INext;
    private int _INextP;
    private int[] _SeedArray;

    // 线程安全的延迟初始化单例
    private static readonly Lazy<ChaosEngine> _lazyShared = new Lazy<ChaosEngine>(
        () => new ChaosEngine(), 
        LazyThreadSafetyMode.ExecutionAndPublication
    );

    // 内部状态锁
    private readonly object _stateLock = new object();

    public int Seed { 
        get { lock(_stateLock) return _Seed; } 
        set { lock(_stateLock) Reseed(value); } 
    }

    private ChaosEngine() {
        Reseed(Environment.TickCount);
    }

    public static ChaosEngine Shared => _lazyShared.Value;

    private void Reseed(int seed) {
        lock(_stateLock) {
            _Seed = seed;
            // 原SeedArray初始化逻辑
            _SeedArray = new int[56];
            int num = (seed == int.MinValue) ? int.MaxValue : Math.Abs(seed);
            int num2 = 161803398 - num;
            _SeedArray[55] = num2;
            int num3 = 1;
            for (int i = 1; i < 55; i++) {
                int num4 = 21 * i % 55;
                _SeedArray[num4] = num3;
                num3 = num2 - num3;
                if (num3 < 0) num3 += int.MaxValue;
                num2 = _SeedArray[num4];
            }
            for (int j = 1; j < 5; j++) {
                for (int k = 1; k < 56; k++) {
                    _SeedArray[k] -= _SeedArray[1 + (k + 30) % 55];
                    if (_SeedArray[k] < 0) _SeedArray[k] += int.MaxValue;
                }
            }
            _INext = 0;
            _INextP = 21;
        }
    }

    public int Next() {
        lock(_stateLock) {
            if (++_INext >= 56) _INext = 1;
            if (++_INextP >= 56) _INextP = 1;
            int num = _SeedArray[_INext] - _SeedArray[_INextP];
            if (num < 0) num += int.MaxValue;
            _SeedArray[_INext] = num;
            return num;
        }
    }
}

关键注意事项

  1. 私有构造函数:必须将构造函数设为私有,防止外部代码创建新的ChaosEngine实例,保证单例唯一性。
  2. 内部状态锁:所有访问或修改_Seed、_INext、_INextP、_SeedArray的操作必须在lock(_stateLock)块内执行,避免多线程竞态条件导致状态不一致。
  3. 锁对象选择:使用私有readonly object作为锁对象,不要用lock(this)或lock(typeof(ChaosEngine)),前者可能被外部代码锁定引发死锁,后者是全局类型锁,易受其他代码干扰。

内容的提问来源于stack exchange,提问作者user3915050

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.23 08:06:20