美文网首页
单例模式的线程安全性

单例模式的线程安全性

作者: Tiny荣 | 来源:发表于2019-04-28 21:17 被阅读0次

    普通的单例模式是线程不安全的,验证方法如下:

    ```

    sealed class Singleton1

        {

            private Singleton1()

            {

            }

            private static Singleton1 instance = null;

            public static Singleton1 Instance

            {

                get

                {

                    if (instance == null)

                    {

                        Console.WriteLine("Cup");

                        instance = new Singleton1();

                    }

                    return instance;

                }

            }

        }

    class Program

        {

            static void Main(string[] args)

            {

                Singleton1 st1 = null;

                Singleton1 st2 = null;

                while (true)

                {

                    Thread t1 = new Thread(() =>

                    {

                        st1 = Singleton1.Instance;

                    });

                    Thread t2 = new Thread(() =>

                    {

                        st2 = Singleton1.Instance;

                    });

                    t1.Start();

                    t2.Start();

                    Thread.Sleep(100);

                }

            }

        }

    ```

    如上所示,打印的结果有很大概率出现两次"Cup",说明两个线程都创建了新的对象,单例被打破了。

    改进方式:加锁

    ```

    sealed class Singleton1

        {

            private Singleton1()

            {

            }

            private static readonly object syncObj = new object();

            private static Singleton1 instance = null;

            public static Singleton1 Instance

            {

                get

                {

                    lock (syncObj)

                    {

                        if (instance == null)

                        {

                            Console.WriteLine("Cup");

                            instance = new Singleton1();

                        }

                    }

                    return instance;

                }

            }

            public void Clear()

            {

                instance = null;

            }

        }

    ```

    运行结果只有一个"Cup",程序在进入代码段时首先判断有没有加锁,如果没有就加锁,另一个线程判断代码已经有锁了,就直接返回,从而保证了单例的唯一性。

    缺点:判断锁状态和尝试加锁操作比较消耗性能

    改进:锁前判断:

    ```

    public static Singleton1 Instance

            {

                get

                {

                    if (instance == null)

                    {

                        lock (syncObj)

                        {

                            if (instance == null)

                            {

                                Console.WriteLine("Cup");

                                instance = new Singleton1();

                            }

                        }

                    }

                    return instance;

                }

            }

    ```

    如此,就只有第一次试图创建实例时要加锁

    有没有不用锁的办法呢,也有:

    ```

    sealed class Singleton1

        {

            private Singleton1()

            {

            }

            private static Singleton1 instance = new Singleton1();

            public static Singleton1 Instance

            {

                get

                {

                    if (instance != null)

                    {

                        return instance;

                    }

                    else

                    {

                        return null;

                    }

                }

            }

        }

    ```

    C#在调用静态构造函数时初始化静态变量,运行时能够确保只调用一次静态构造函数。但这种机制不确定在其他语言中也存在

    如果局限于C#中,还有更优化的方法:

    ```

    sealed class Singleton1

        {

            private Singleton1()

            {

            }

            public static Singleton1 Instance

            {

                get

                {

                    return Nested.instance;

                }

            }

            class Nested

            {

                static Nested()

                {

                }

                internal static readonly Singleton1 instance = new Singleton1();

            }

        }

    ```

    将创建实例的时机局限在获取Instance时。

    相关文章

      网友评论

          本文标题:单例模式的线程安全性

          本文链接:https://www.haomeiwen.com/subject/rehsnqtx.html