温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Lazy<T>的使用方式(可实现单例模式)

发布时间:2020-06-11 19:16:46 来源:网络 阅读:2373 作者:cnn237111 栏目:编程语言

Lazy<T>是延迟对象,通过它可以延迟创建T对象,也就是说,虽然已经声明了对象,但是实际上只有在使用T对象的时候,才会去创建这个对象。如下代码:

class MyClass
    {
        public MyClass()
        {
            Console.WriteLine("MyClass对象创建,其标识:{0}", this.GetHashCode());
        }
    }
 static void Main(string[] args)
        {
            Console.WriteLine(DateTime.Now);
            Lazy<MyClass> lazyObj = new Lazy<MyClass>();
            Thread.Sleep(2000);//等待2秒钟
            Console.WriteLine(DateTime.Now);
            Console.WriteLine("MyClass对象的HashCode={0}", lazyObj.Value.GetHashCode());
            Console.WriteLine("MyClass对象的HashCode={0}", lazyObj.Value.GetHashCode());
            Console.WriteLine("MyClass对象的HashCode={0}", lazyObj.Value.GetHashCode());
            Console.WriteLine("MyClass对象的HashCode={0}", lazyObj.Value.GetHashCode());
         }

得到结果为:

Lazy<T>的使用方式(可实现单例模式)

可以看到,虽然在25秒的时候,声明了 Lazy<MyClass>对象,但是MyClass对象的构造函数并没有马上调用。

程序延迟2秒后,打印lazyObj.Value中的MyClass对象的HashCode的时候,程序发现MyClass对象还未创建,才去创建,调用MyClass的构造函数。一旦创建完毕后,之后再次调用lazyObj.Value中的MyClass对象,也不会再去创建该对象。

在单线程的环境下,使用Lazy的意义也不是很明显。

在多线程环境下:

创建Lazy对象的时候,使用它的重载构造函数之一:

public Lazy(Func<T> valueFactory, LazyThreadSafetyMode mode);

参数valueFactory是一个委托,通过他来创建T对象。mode则是线程安全性模式。是一个枚举值,有三种值:

None

PublicationOnly

ExecutionAndPublication

如下一段测试代码:


class Program
    {
        static void Main(string[] args)
        {
             Lazy<MyClass> lazyObj = new Lazy<MyClass>(() => { return new MyClass(); }, LazyThreadSafetyMode.None);//此处修改mode的参数(None,PublicationOnly,ExecutionAndPublication),看对程序有何影响
            for (int i = 0; i < 10; i++)
            {
                Thread th = new Thread(() => { Console.WriteLine("线程调用对象{0}", lazyObj.Value.GetHashCode()); });
                th.Start();
            }
        }
    }
    class MyClass
    {
        public MyClass()
        {
            Console.WriteLine("MyClass对象创建,其标识:{0}", this.GetHashCode());
        }
    }

当Mode参数为LazyThreadSafetyMode.None时,得到的结果如下:

Lazy<T>的使用方式(可实现单例模式)

这错误原因是没有创建MyClass实例前,就有线程去访问对象的GetHashCode()方法了。这也说明了如果选用LazyThreadSafetyMode.None,那就不保证线程在访问Lazy对象的lazyObj.Value前先创建对象。这种情况下,当有些线程在启动前,很幸运的,该对象已经创建了,有些线程启动前则很不幸,对象并没有创建。因此会出现上面的那种异常。

当Mode参数为LazyThreadSafetyMode.PublicationOnly时,得到的结果如下:

Lazy<T>的使用方式(可实现单例模式)

可能每次运行的结果不同,但这次运行中可以看到,MyClass的构造函数被运行了3次,但是即使有3个对象创建了,在每次调用该对象时,只使用其中的一个对象。(不确定使用的是最先生成的那个对象,因为测试的时候,发现有时候使用的对象是后生成的。不过根据本人理解应该是使用最先生成的对象,由于在并发过程中,最先生成的对象不一定最先打印出来)

当Mode参数为LazyThreadSafetyMode.ExecutionAndPublication时,得到的结果如下:

Lazy<T>的使用方式(可实现单例模式)

使用LazyThreadSafetyMode.ExecutionAndPublication,保证了对象只被创建一次。基于这个特性,可以使用LazyThreadSafetyMode.ExecutionAndPublication方式,实现在多线程下的单例模式。但是要注意:此时Lazy对象仅保证多个线程访问的是同一个对象,但不保证多线程访问对象时候是否同步,因此,如果要确保多线程访问同步访问同一个对象,最好还是采取lock等方式。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI