单例模式

Posted hhzblogs

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了单例模式相关的知识,希望对你有一定的参考价值。

单例模式,是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中,应用该模式的一个类只有一个实例。即一个类只有一个对象实例。

在我们平常的开发中,我们需要一些辅助类,比如Redis辅助类,一般把一些初始化的工作放在构造函数中,然后写一些方法来完成Redis要作的一些具体的功能。但是有一个问题,我们每次调用的时候都会去 实例化这个辅助类,然后去调用一些方法。然而每次实例化的时候构造函数里面作的事情都会被重复的做一遍。这与我们预期的并不符合。。。

接下来我们来演示下怎样实现所谓的单例模式。

1.单线程模式下实现单例

    public class Singleton
    {
        long lResult = 0;
        private Singleton()
        {
            Console.WriteLine("被实例化了一次");
            for (int i = 0; i < 100000000; i++)
            {
                lResult += i;
            }
        }
        public long GetResult()
        {
            return lResult;
        }
        private static Singleton _singleton { get; set; }
        public static Singleton CreateInstance()
        {
            if (_singleton == null)
            {
                _singleton = new Singleton();
            }
            return _singleton;
        }
    }

调用:

    for (int i = 0; i < 10; i++)
    {
        Singleton singleton = Singleton.CreateInstance();
        Console.WriteLine(singleton.GetResult());
    }

结果如下:

技术分享图片

2.多线程模式下实现单例

我们来将调用的地方修改下:

    List<Task> tasks = new List<Task>();
    TaskFactory taskFactory = new TaskFactory();
    for (int i = 0; i < 10; i++)
    {
        tasks.Add(taskFactory.StartNew(() =>
        {
            Singleton singleton = Singleton.CreateInstance();
            Console.WriteLine(singleton.GetResult());
        }));
    }
    Task.WaitAll(tasks.ToArray());

来看看我们将得到结果是什么:

技术分享图片

从上面的结果可以看出,第一次只能用于单线程的模式下,多线程下并不行。那么怎样才能让多线程下也可以实现单例呢?

我们只需要修改下辅助类内部即可(用lock来实现)。

修改后的代码:

public class Singleton
    {
        private static object singleton_lock = new object();
        long lResult = 0;
        private Singleton()
        {
            Console.WriteLine("被实例化了一次");
            for (int i = 0; i < 100000000; i++)
            {
                lResult += i;
            }
        }
        public long GetResult()
        {
            return lResult;
        }
        private static Singleton _singleton { get; set; }
        public static Singleton CreateInstance()
        {
            lock (singleton_lock)
            {
                if (_singleton == null)
                {
                    _singleton = new Singleton();
                }
            }
            return _singleton;
        }
    }

结果如下:

技术分享图片

上面就实现了我们的多线程下使用单例,当然上面的代码我们还是可以优化下,在lock之前,我们可以再用一个 if (_singleton == null) 来判断一下,至于为什么,自己思考下应该就明白了。

3.使用静态构造函数

辅助类内部代码:

    public class SingletonSecond
    {
        private static object singletonSecond_lock = new object();
        long lResult = 0;
        private SingletonSecond()
        {
            Console.WriteLine("被实例化了一次");
            for (int i = 0; i < 100000000; i++)
            {
                lResult += i;
            }
        }
        public long GetResult()
        {
            return lResult;
        }
        private static SingletonSecond _singletonSecond { get; set; }
        static SingletonSecond()
        {
            _singletonSecond = new SingletonSecond();
        }
        public static SingletonSecond CreateInstance()
        {
            return _singletonSecond;
        }
    }

调用:

    List<Task> tasks = new List<Task>();
    TaskFactory taskFactory = new TaskFactory();
    for (int i = 0; i < 10; i++)
    {
        tasks.Add(taskFactory.StartNew(() =>
        {
            SingletonSecond singleton = SingletonSecond.CreateInstance();
            Console.WriteLine(singleton.GetResult());
        }));
    }
    Task.WaitAll(tasks.ToArray());

结果如下:

技术分享图片

4.静态对象

内部代码:

    public class SingletonThird
    {
        private static object singletonSecond_lock = new object();
        long lResult = 0;
        private SingletonThird()
        {
            Console.WriteLine("被实例化了一次");
            for (int i = 0; i < 100000000; i++)
            {
                lResult += i;
            }
        }
        public long GetResult()
        {
            return lResult;
        }
        private static SingletonThird _singletonThird = new SingletonThird();
        public static SingletonThird CreateInstance()
        {
            return _singletonThird;
        }
    }

调用代码:

    List<Task> tasks = new List<Task>();
    TaskFactory taskFactory = new TaskFactory();
    for (int i = 0; i < 10; i++)
    {
        tasks.Add(taskFactory.StartNew(() =>
        {
            SingletonThird singleton = SingletonThird.CreateInstance();
            Console.WriteLine(singleton.GetResult());
        }));
    }
    Task.WaitAll(tasks.ToArray());

结果如下:

技术分享图片

以上三种方式都可以用来实现单例模式。当然还有别的更多的方式,这里只是举一些例子学习用。

源码:https://github.com/houzhenhuang/DesignPattern

 

以上是关于单例模式的主要内容,如果未能解决你的问题,请参考以下文章

常用代码片段

性能比较好的单例写法

片段作为 Android 中的单例

单例片段或保存网页视图状态

你熟悉的设计模式都有哪些?写出单例模式的实现代码

单例模式以及静态代码块