关于线程安全的单例模式的讨论

其实这个问题断断续续研究了1个多星期了 主要是想开一条线程来监听用户登录的状态 好吧 还是打点标点符号好了。

说这个事情之前不得不说的一些背景。首先呢,我是写过多线程的,但是失败了。那是3年前读大学的时候,自己想着不按老师提出的课题,硬是要写一个简单的动作游戏。然后,老师说不能用IDE环境,只能用TXT,然后只有两个星期时间,那个是JAVA的,编译的时候还得用cmd来玩~~然后我写出来的程序非常诡异~ 然后只有60多分吧。然后我发现大家貌似都用MyEclipse或者Netbeans来写,好像。。我只能说那个老师鼓励学生的方式有点奇怪。。客观来说,那个游戏是失败的,我的努力和产出的结果让我针对自己的智商进行了重新评估~那时候两个星期基本很多时候都是在看JAVA的多线程,那个。。。看不懂~~然后埋下了深深的自卑和挫折感。。。

然后最近做项目里用户管理这块,由于这个项目是2年前的我来构建的。那可是杠杠的本B学校实验项目水平~ 用户这块也是用Session来判定的~比较简单~ 然后想着趁这个机会重构一下我的项目~主要是针对后台架构这块做出一些调整。然后觉得后台这块必须要用到多线程技术~ 因为分布式的应用或者现在开始火起来的BigPip都用到了多线程技术。然后遇到了需要用单例的情况,然后遇到了单例+多线程。。然后一切就这么发生了~~很自然的 直接遇到了多线程实例化单例类。。。

既然说到单例,不得不说单例的几种模式:

第一种,类定义的时候就加载了~:

public final class EagerSingleton  
{  
    private static EagerSingleton singObj = new EagerSingleton();  
  
    private EagerSingleton(){}  
  
    public static EagerSingleton getSingleInstance(){  
       return singObj;
    }  
}  

第二种是延迟加载:

public final class LazySingleton  
{  
    private static LazySingleton singObj = null;  
  
    private LazySingleton(){  
    }  
  
    public static LazySingleton getSingleInstance(){  
        if(null == singObj ) singObj = new LazySingleton();
          return singObj;
    }  
} 

然后是延迟加载的亚种,也是这次故事的主角--双重检查锁(Double-Checked Lock)

public final class DoubleCheckedSingleton  
{  
    private static DoubleCheckedSingletonsingObj = null;  
  
    private DoubleCheckedSingleton(){  
    }  
  
    public static DoubleCheckedSingleton getSingleInstance(){  
        if(null == singObj ) {
              Synchronized(DoubleCheckedSingleton.class){
                     if(null == singObj)
                           singObj = new DoubleCheckedSingleton();
              }
         }
       return singObj;
    }  
}  

文章里面提出了双重检查锁会有一个情况是返回不完全对象,因此这种锁机制是不安全的。然后产生了一下的产物:(JAVA的)

public class Singleton    
{    
    private static class SingletonHolder    
    {    
        public final static Singleton instance = new Singleton();    
    }    
   
    public static Singleton getInstance()    
    {    
        return SingletonHolder.instance;    
    }    
}  

这里用到了JAVA的优势~,但是我的是C#的项目~。故事继续:

然后,我找到了一个小伙子(刚毕业半年吧)跟他一起商量~ 我跟他说明了情况(主要介绍了双重锁这些东西),他说要不给一个中间变量,让他实例完了再把这个中间变量赋值给返回的变量。然后参照双重锁的代码:

public class DoubleCheckedSingleton  
{  
    private static DoubleCheckedSingletonsingObj = null;  
  
    private DoubleCheckedSingleton(){  
    }  
  
    public static DoubleCheckedSingleton getSingleInstance(){  
        if(null == singObj ) {
              Synchronized(DoubleCheckedSingleton.class){
                     if(null == singObj)
                           DoubleCheckedSingleton buffer = new DoubleCheckedSingleton()
                           singObj = buffer;
              }
         }
       return singObj;
    }  
}  

这样在实例化的时候singObj的值始终为null,因此避免了返回不完全对象的可能性了。

然后我查了一些C#引用类型赋值的资料,觉得这个办法是可行的,后生可畏啊,有点失落,吾等互勉吧~

饮水思源,代码部分参考这里:

线程安全的单例模式 http://blog.sina.com.cn/s/blog_75247c770100yxpb.html;

最后带着不甘感谢我的同事剑周。

----循例的一段签名:山外有山,人外有人,吾当自强,诸君共勉

原文地址:https://www.cnblogs.com/gssl/p/3463473.html