zoukankan      html  css  js  c++  java
  • 解密Lazy<T>

    1.Lazy<T>的使用

    无意间看到一段代码,在创建对象的时候使用了Lazy,顾名思义Lazy肯定是延迟加载,那么它具体是如何创建对象,什么时候创建对象了? 先看这段示列代码:

        public class OrderController : Controller
        {
            private readonly Lazy<OrderService> _orderSrv = new Lazy<OrderService>();
            
            public ActionResult CreateOrder(OrderModel model)
            {
                var result = _orderSrv.Value.CreateOrder(model);
                return Json(result);
            }
        }

    使用非常简单,把 OrderService 放到Lazy<T> 中,然后 _orderSrv.Value 的时候才真正创建OrderService 对象。

    那么问题来,是不是每次_orderSrv.Value 一下,就创建一个对象了? 想到这里,程序猿基本的条件反射,对着Lazy按下F12。

     

    构造函数中,有个isThreadSafe的参数,默认是true。ok,参考了msdn的例子,我们来测试看看。 

            static void Main(string[] args)
            {            
                Lazy<int> number = new Lazy<int>(() => Thread.CurrentThread.ManagedThreadId);
    
                Thread t1 = new Thread(() => 
                    Console.WriteLine("number on t1 = {0} ThreadID = {1}"
    ,number.Value, Thread.CurrentThread.ManagedThreadId)); t1.Start(); Thread t2 = new Thread(() => Console.WriteLine("number on t2 = {0} ThreadID = {1}"
    ,number.Value, Thread.CurrentThread.ManagedThreadId)); t2.Start(); Thread t3 = new Thread(() => Console.WriteLine("number on t3 = {0} ThreadID = {1}"
    , number.Value,Thread.CurrentThread.ManagedThreadId)); t3.Start(); Console.ReadLine(); }

     结果:

     

     很明显,number 被ID=10的线程初始化后,值一直没有改变,说明三个线程用的是同一个实例。

     再试试 isThreadSafe=false 。

     Lazy<int> number = new Lazy<int>(() => Thread.CurrentThread.ManagedThreadId, false);

     结果(1):

     

    number实例被ID=11的线程使用后,其他线程就不能再正确使用了,number.value=0 说明 int并没有被赋值。

    结果(2):

    直接报错了,我的理解是,Lazy此时并不支持多线程并发。 

    2.Lazy<T> 的 valueFactory

    继续在f12中找到解释:

     

    结合我们上面的例子,可分析出,valueFactory是个委托,number.value的时候就是由valueFactory来创建这个实例。

    看到这里,我们发现Lazy<T> 还是很强大的,可以用T的默认构造函数来创建实例也可以用指定的Func来创建实例,而且还支持多线程安全。 

    3.Lazy<T>的工作原理

     用反编译插件看看代码: 

          static Lazy()
            {
                Lazy<T>.ALREADY_INVOKED_SENTINEL = () => default(T);
                Lazy<T>.PUBLICATION_ONLY_SENTINEL = new object();
            }
            [__DynamicallyInvokable]
            public Lazy(Func<T> valueFactory, LazyThreadSafetyMode mode)
            {
                if (valueFactory == null)
                {
                    throw new ArgumentNullException("valueFactory");
                }
                this.m_threadSafeObj = Lazy<T>.GetObjectFromMode(mode);
                this.m_valueFactory = valueFactory;
            }

     看到 default(T) 和 this.m_valueFactory = valueFactory 大概也知道是如何创建实例了吧。

     本文博客园地址:http://www.cnblogs.com/struggle999/p/6917067.html 

  • 相关阅读:
    千万别用树套树 【题意:有多少线段完全覆盖某一线段【树状数组维护】】【模板题】
    Codeforces Round #590 (Div. 3)【D题:26棵树状数组维护字符出现次数】
    Codeforces Round #590 (Div. 3)【D题:维护26棵树状数组【好题】】
    Codeforces Round #350 (Div. 2) A B C D1 D2 水题【D2 【二分+枚举】好题】
    AtCoder Beginner Contest 142【D题】【判断素数的模板+求一个数的因子的模板】
    AtCoder Beginner Contest 116 D
    序列自动机【模板】
    题解 CF1428G Lucky Numbers (Easy Version and Hard Version)
    题解 CF1428F Fruit Sequences
    题解 P5401 [CTS2019]珍珠
  • 原文地址:https://www.cnblogs.com/struggle999/p/6917067.html
Copyright © 2011-2022 走看看