• 选学校
  • 高中毕后选择什么学校好
  • 启蒙星
  • 北大青鸟课程介绍
  • 北大青鸟助你走上高级软件工程师修炼之路
  • 转行不是梦,学北大青鸟IT培训
  • 北大青鸟辉煌12年
  • 株洲北大青鸟校区升级

您现在的位置:株洲北大青鸟 >> >> 师资力量>> 技术天地

师资力量
开班信息
输入姓名手机号码预约试听课程
姓  名:*
手机号:*
创业摇篮班
开班日期:10月15日
招生人数:25
就业直通班
开班日期:10月31日
招生人数:25
就业精英班
开班日期:9月13日
招生人数:已满
技术天地
  • 单例模式的详细讲解流程
  • 发表日期:2008/5/13 9:38:57 阅读数:500  
  •  
  •                                         单例模式的详细讲解流程
    株洲北大青鸟优秀作者:李治
     
         单例模式的作用是确保一个类只有一个实例。比如,windows中只能打开一个任务管理器,系统只允许有一个登录用户等。我们在讲解单例模式时演示的代码一般为以下结构。
        class CurrentUser
        {
            private static CurrentUser _user;
            public static object obj = new object();
            private CurrentUser()
            {
            }
     
            public static CurrentUser CreateUser()
            {
                if (_user == null)
                {
                    lock (CurrentUser.obj)
                    {
                        if (_user == null)
                        {
                            _user = new CurrentUser();
                        }
                    }
                }
                return _user;
            }
        }
    这段代码并不复杂,但其中的机制却比较复杂,那该如何在课堂上讲解呢。我主要的思路就是引导法,也就是发现问题,分析问题,解决问题的方法。现在我们来详细分解下具体步骤:
    1 首先演示一个类,这个类有一个属性。
        class CurrentUser{
            public int _userId;
        }
    很显然,我们可以随意创建这个类的任意多个对象。那怎么才能控制用户随意创建对象呢?把构造函数声明成私有,再专门提供一个方法来做实例化。
        class CurrentUser{
            public int _userId;
            private CurrentUser(){
            }
        }
     
    2 用户现在不能随意实例化了,当然我们还得提供一个方法来创建对象,并且控制只会创建一个对象。
        class CurrentUser{
            public int _userId;
            private CurrentUser(){
            }
            private static CurrentUser _user = new CurrentUser();
            public static CurrentUser GetUser(){
                return _user;
            } 
      }
    我们定义了一个静态变量_user来存储对象,并提供一个静态方法返回_user。用这种方法可以很好的解决问题,但是也存在缺点,由于_user在程序运行的时候就对创建对象,所以不能延迟_user的实例化。
    3 对于以上的问题,我们可以用这种方法来延迟实例化:
        class CurrentUser{
            public int _userId;
            private CurrentUser(){
            }
            private static CurrentUser _user;
            public static CurrentUser GetUser()
            {
                if (_user == null) {
                    _user = new CurrentUser();
                }
                return _user;
            }
        }
    用这种方法我们可以在GetUser()第一次被调用的时候才被实例,延迟了对象的创建。但是,问题来了,使用多线程可能创建多个对象,我们看看这段代码。
        class Program{
            static void Main(string[] args)
            {
                Del del = new Del(CurrentUser.GetUser);
                IAsyncResult ar = del.BeginInvoke(null, null);//使用异步调用来创建对象
                CurrentUser.GetUser();//主线程创建对象
                del.EndInvoke(ar);//结束异步调用
                Console.WriteLine(CurrentUser._objNumber);
            }
        }
        public delegate CurrentUser Del();
        public class CurrentUser
        {
            public int _userId;
            public static int _objNumber = 0;
            private CurrentUser(){
                CurrentUser._objNumber++;
            }
            private static CurrentUser _user;
            public static CurrentUser GetUser()
            {
                if (_user == null)
                {
                   Thread.Sleep(200);//该代码使得线程时间片切换更加明显,以提高创建多个对象的概率
                    _user = new CurrentUser();
                }
                return _user;
            }
        }
    这段代码的运行结果为2,也就是说创建了2个对象,为什么呢?我们分析下过程:
    1)          线程1执行GetUser(),并判断_user为null
    2)          在线程1创建对象之前,时间片结束,线程2开始执行
    3)          线程2执行GetUser(),并判断_user为null,并创建对象。
    4)          线程1恢复执行,再创建一个对象。
    4 为了解决以上问题,我们必须使用同步来创建对象,如下
        public class CurrentUser{
            public int _userId;
            public static int _objNumber = 0;
            public static object obj = new object();
            private CurrentUser(){
                CurrentUser._objNumber++;
            }
            private static CurrentUser _user;
            public static CurrentUser GetUser()
            {
                lock (obj){
                    if (_user == null) {
                        _user = new CurrentUser();
                    }
                }
                return _user;
            }
        }
    我们在创建对象是使用同步,就解决了多线程创建多个对象的问题。我们再看看代码的执行:
    1)线程1执行GetUser(),锁定对象,并判断_user为null
    2)在线程1创建对象之前,时间片结束,线程2开始执行
    3)线程2执行GetUser(),但由于互斥锁的存在,线程2无法执行里面的代码,于是等待线程1释放锁。
    4)线程1恢复执行,创建对象,并释放锁。
    5)线程2恢复执行,由于对象不为null,所以不会再次创建对象。
     
    但是问题又来了,用户每次调用GetUser()都需要同步,这就影响了性能,我们可以通过如下方法解决这个问题。
        public class CurrentUser
        {
            public int _userId;
            public static int _objNumber = 0;
            public static object obj = new object();
            private CurrentUser(){
                CurrentUser._objNumber++;
            }
            private static CurrentUser _user;
            public static CurrentUser GetUser()
            {
                if (_user == null) {
                    lock (obj) {
                        if (_user == null) {
                            _user = new CurrentUser();
                        }
                    }
                }
                return _user;
            }
        }
    在同步前再作一次检查即可解决这个问题,这就是著名的双检锁算法。
上一篇:jsp+servlet 路径状态的测试
下一篇:Oracle基于时间点的恢复
分享到:

版权所有 ©株洲健坤科技职业培训学校    学校地址:株洲市天元区黄山路205号健坤大厦(天元区消防中队对面)

咨询报名热线:400-8812-866    邮箱地址:4008812866@b.qq.com   备案号: 湘ICP备10202015号  

北大青鸟学费是多少 湖南北大青鸟怎么样
株洲北大青鸟好不好 株洲北大青鸟学费多少 株洲北大青鸟学校这么样
秒速时时彩官方网站