高并发访问环境下二个方法代码的对比

先展示一段代码出来。方法 Method1Method2二方法的功能都相同:首先检查字典中是否有缓存的类的属性信息,如果没有则反射获取类的属性信息,放入缓存字典并返回;如果有,则返回缓存字典中的属性信息。

大家看下面的 Method1 Method2 二方法有什么区别?

private static Dictionary<Type, Dictionary<string, PropertyInfo>> _classProperties = new Dictionary<Type, Dictionary<string, PropertyInfo>>();

        // 方法 Method1

        private static Dictionary<string, PropertyInfo> Method1(Type pType)

        {

            Dictionary<string, PropertyInfo> result;

            if (!_classProperties.TryGetValue(pType, out result))

            {

                lock (_classProperties)

                {

                    if (!_classProperties.TryGetValue(pType, out result))

                    {

                        result = new Dictionary<string, PropertyInfo>();

                        // 获取类的所有公开属性

                        PropertyInfo[] pis = pType.GetProperties(BindingFlags.Public | BindingFlags.Instance);

                        foreach (PropertyInfo pi in pis)

                        {

                            result.Add(pi.Name, pi);

                        }

                        _classProperties[pType] = result;

                    }

                }

            }

            return result;

        }

       // 方法 Method2

        private static Dictionary<string, PropertyInfo> Method2(Type pType)

        {

            Dictionary<string, PropertyInfo> result;

            if (!_classProperties.TryGetValue(pType, out result))

            {

                lock (_classProperties)

                {

                    if (!_classProperties.TryGetValue(pType, out result))

                    {

                        _classProperties[pType] = result = new Dictionary<string, PropertyInfo>();

                        // 获取类的所有公开属性

                        PropertyInfo[] pis = pType.GetProperties(BindingFlags.Public | BindingFlags.Instance);

                        foreach (PropertyInfo pi in pis)

                        {

                            result.Add(pi.Name, pi);

                        }

                    }

                }

            }

            return result;

        }

区别在于,我把 Method1中以红色字体标示的二行代码,在 Method2中用一行代码代替了。肯定有人会说,这不是很简单的代码吗!嗯,看起来是很简单。在大多情况下,二个方法谁都可以代替谁。然而,当在高并发的生产环境下,方法二却是有BUG的。原因何在?

    方法一分析:当在同一时间(时段)有多个外部代码首次调用方法一时,由于缓存字典中没有属性信息,所有的调用点都阻塞在 lock(_classProperties) 处,而只有最先调用的代码进入 lock 内部执行,lock 内部执行一系列动作后,最后把获取到的类属性信息加入缓存字典中返回并释放锁(记住,是最后才加入缓存),释放锁后,其它等待的调用点就一窝锋的进入 lock 内部,由于此时缓存中已经有了类属性信息,在从缓存中获取后直接返回,不再反射。在第一个调用点锁定期间,如果有另外的调用点调用,也会等待第一个锁结束后继续。

方法二分析:与方法一的主要区别在于,如果第一个调用点在锁定期间,代码执行在_classProperties[pType] = result = new Dictionary<string, PropertyInfo>() 行的同时,又有第二个调用点调用方法二,则第二个调用点在缓存字典中能够得到类对应的内容,但是,此时第一个调用点还没有执行完,也就是说,字典中的属性信息是不完整的,那么第二个调用点的外部代码在往下执行时,有可能会出错。这就是方法二为什么会有BUG的原因之所在。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值