博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
单例模式易错分析
阅读量:4922 次
发布时间:2019-06-11

本文共 3249 字,大约阅读时间需要 10 分钟。

最近在学些设计模式,今天记录的是单例模式,单例模式在平时的工作中运用的还是比较多的,是一种常用的软件设计模式,通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源。如果希望在系统中某个类的对象只能存在一个,单例模式将是您的是最好的解决方案。

先上代码:

public class SigletonCounter    {        //static SigletonCounter instance = new SigletonCounter();        static SigletonCounter instance = null;//将类定义为静态类        public static SigletonCounter Instance        {            get            {                if (instance == null)                {                    instance = new SigletonCounter();//实例化该类                }                return instance;            }        }        private int totnum = 0;//计数用        public void add()        {            totnum++;        }        public int GetCounter()        {            return totnum;        }  }

 

以上的代码就是一个简单的单例实例了,在一般的单一线程程序中,看上去是足够了,但是在多线程的情况下似乎就达不到单例的效果了,有可能出现两个线程同时判断了if (instance == null)这个方法,导致了存在两个实例,造成错误,下面我们来验证下这样的情况,上代码:

///         /// 用于显示        ///         void Write()        {            string results = "";            SigletonCounter mycounter = SigletonCounter.Instance;            for (int i = 0; i < 3; i++)            {                mycounter.add();                results += Thread.CurrentThread.Name.ToString() + "对应";                results += "当前的计数:";                results += mycounter.GetCounter().ToString();                results += "\n";                Console .WriteLine ( results);                results = "";            }        }
{
       Thread thread0 = Thread.CurrentThread; thread0.Name = "线程 0"; Thread thread1 = new Thread(new ThreadStart(DOwork)); thread1.Name = "线程 1"; Thread thread2 = new Thread(new ThreadStart(DOwork)); thread2.Name = "线程 2"; Thread thread3 = new Thread(new ThreadStart(DOwork)); thread3.Name = "线程 3"; thread1.Start(); thread2.Start(); thread3.Start(); Write();        }

运行一下结果为:

线程 3对应当前的计数:1

线程 3对应当前的计数:3

线程 3对应当前的计数:4

线程 1对应当前的计数:1

线程 1对应当前的计数:2

线程 1对应当前的计数:3

线程 0对应当前的计数:5

线程 0对应当前的计数:6

线程 0对应当前的计数:7

线程 2对应当前的计数:2

线程 2对应当前的计数:8

线程 2对应当前的计数:9

从上面的结果看,和预测的结果是相符合的,其中出现了重复的数,按照单例模式的理论是不应该出现该问题的,totnum的值应该是唯一的,但是事实摆在面前,我们得去解决它。

现在对程序SigletonCounter类做改进如下:

static SigletonCounter instance = null;//将类定义为静态类        private int totnum = 0;//计数用        static readonly object padlock = new object();        public static SigletonCounter Instance        {            get            {                if (instance == null)//多加一次判断是因为,此判断在此可提升性能,少做lock操作                {                    lock (padlock)                    {                        if (instance == null)                        {                            instance = new SigletonCounter();                        }                    }                }                return instance;            }        }        public void add()        {            totnum++;        }        public int GetCounter()        {            return totnum;        }

运行得到结果是:

线程 1对应当前的计数:1

线程 1对应当前的计数:2

线程 1对应当前的计数:3

线程 0对应当前的计数:4

线程 0对应当前的计数:5

线程 0对应当前的计数:6

线程 3对应当前的计数:7

线程 3对应当前的计数:8

线程 3对应当前的计数:9

线程 2对应当前的计数:10

线程 2对应当前的计数:11

线程 2对应当前的计数:12

这样的就达到我们的目的了,在同一个时刻加了锁的那部分程序只有一个线程可以进入,避免了同时判断造成的错误,

 

转载于:https://www.cnblogs.com/ouzining/p/4172172.html

你可能感兴趣的文章
logistic softmax
查看>>
函数模拟sort快排
查看>>
WPF Knowledge Points - 默认视图(DefaultView),CollectionSourceView,CollectionView的区别
查看>>
C#开源项目大全
查看>>
docker 小技巧 docker network create br-name 指定IP地址
查看>>
decode函数
查看>>
通过jvm 查看死锁
查看>>
多线程(大量密集的I/O处理);多进程(大量密集并行计算);Scrapy(异步,协程)...
查看>>
rabbitmq route
查看>>
恢复为TrustedInstaller权限
查看>>
怎样利用细碎时间达到整体学习的效果
查看>>
C# 位数组
查看>>
当递归遇到synchronized
查看>>
HDU - 2141 : Can you find it?
查看>>
bzoj1093 [ZJOI2007]最大半联通子图 缩点 + 拓扑序
查看>>
《Java并发编程的艺术》之线程池(二)
查看>>
SCP注意事项
查看>>
英国NHS
查看>>
ScrollView嵌套GridView和ListView行高问题
查看>>
测试秒杀新版本3.5 stieserver cms
查看>>