延迟计算导致假锁

延迟计算导致假锁

程序中有时会需要用到延迟计算。比如程序启动时计算尽可能少的内容可以加快启动速度等。

延迟计算有好处也有坏处。好处:按需计算不集中占用资源,用到的时候才进行计算,一些没用到的内容永不计算;坏处:假如需要用到时对象计算耗时过长,程序响应就会较慢,用户体验较差。所以用不用延迟计算要根据实际情况仔细掂量,适当的优化,做到真正的削峰填谷。

C#的lambada的延迟计算特性,延迟计算的代码包含在锁内,可是实际计算时却不在锁内,造成假锁。

实例:

class Program
{
    private static readonly List<string> TextList = new List<string>();
    private static readonly object SyncLock = new object();
	
    static void Main()
    {
        new Thread(Add)
        {
            IsBackground = true
        }.Start();

        new Thread(Remove)
        {
            IsBackground = true
        }.Start();

        new Thread(Query)
        {
            IsBackground = true
        }.Start();

        Console.ReadKey();
    }

    private static void Query()
    {
        try
        {
            while (true)
            {
                var query = GetTexts();
                Thread.Sleep(10);
                var x = query.ToArray();
                Console.WriteLine(x.Length);
            }
        }
        catch (Exception e)
        {
            throw;
        }
    }

    private static IEnumerable<string> GetTexts()
    {
        lock (SyncLock)
        {
            return TextList.Select(item => item.ToString());
        }
    }

    private static void Add()
    {
        while (true)
        {
            lock (SyncLock)
            {
                if (TextList.Count <= 0)
                {
                    TextList.AddRange(Enumerable.Range(0, 100000).Select(item => item.ToString()));
                }
            }
        }
    }

    private static void Remove()
    {
        while (true)
        {
            lock (SyncLock)
            {
                if (TextList.Count > 0)
                {
                    TextList.RemoveAt(0);
                }
            }
        }
    }
}

多线程的方式对集合进行增删查,查采用lambda的延时计算。

运行上面的代码会报以下错误: 集合已被修改

延迟加载不应该出锁,出锁了导致这样一个错误。

由以上可知,不要在锁中使用延时计算,即使想用这种写法也要在锁内完成计算。

打赏