单例模式代码兑现与解析,java实现

单例模式代码实现与解析,java实现
Singleton模式和它的变体Double-Checked Locking模式比较简单,而且非常常用.

按照<设计模式>一书 ,singleton 意图:保证一个类有且仅有一个实例,并对外提供一个访问它的全局访问点.
其具体的关键特征和工作原理,不在此文表述,可以参看<Design Patterns Explained>一书.

以下逐步提供代码实现:

代码1.
最经典的实现:  把class中所有的methods和fields/status全部声明为static,
然后初始化还可以用static关键字,显示的初始化.
(有兴趣的请参见<Thinking.In.Java.4th.Edition>一书中的节Explicit static initialization)

示例:
public class StaticSingleton {
  public static int count =0;
  private static String name =null; 
  static {
    name  = "singleton";
  }

  public static String getName() {
    return name;
  }

  public static void setName(String name) {
    StaticSingleton.name = name;
  }
}



假设该StaticSingleton 有许多的methods和fields/status,那么我们的代码就有所多static关键字了.
这样对于声明的methods和fields/status都要打上static关键字.似乎有点累,
书写代码后,看来似乎有点不美观,
且对于JDK6开始,StaticSingleton 对外的引用全要写成StaticSingleton.A ,或StaticSingleton.getA()之类的,
让StaticSingleton 的局外使用不够简洁.

那么产生代码2.

代码2.Eager式的Singleton.  (实际上多线程不可行)
示例:
public class EagerSingleton1 {
  private static EagerSingleton1 instance;
  private EagerSingleton1() {
  }
  public static EagerSingleton1 getInstance() {
    if( instance == null ) instance = new EagerSingleton1();
    return instance;
  }
}

带父类的.
示例:
public class EagerSingleton1 extends SuperSingleton {
  private static SuperSingleton instance;
  private EagerSingleton1() {
  }
  public static SuperSingleton getInstance() {
    if( instance == null ) instance = new EagerSingleton1();
    return instance;
  }
}



代码只能用于单线程情况,假设多线程情况下,那么就会出现问题.
如两个线程都执行EagerSingleton1 的new 操作,那后果就可以想象一下.
因此在多线程下我们加入线程同步代码像代码4  或则 像代码3.
代码3.
示例:
public class EagerSingleton {
  //是否带final,视情况而定.
  private static EagerSingleton instance = new EagerSingleton();
  private EagerSingleton() {
  }
  public static EagerSingleton getInstance() {      
    return instance;
  } 
}

带父类的代码(略).


代码4.  (针对JAVA,多线程还是不可行,原因JAVA编译器本身优化工作)
针对代码2解决方法:在检查null之后进行同步(doSync()),然后再检查一次,确保实例尚未创建.
这就称为Double-Checked Locking模式.
实际上这是C++转换成JAVA的.

可以带父类的:
示例:
public class LazySingleton extends SuperSingleton {
  // 是否带final,视情况而定.
  private static volatile LazySingleton instance = null;
  private LazySingleton() {
  }
  public static SuperSingleton getInstance() {
    if( instance == null ) {
      synchronized (LazySingleton.class) {
        if( instance == null ) {
          instance = new LazySingleton();
        }
      }
    }
    return instance;
  }
  //private synchronized static void doSync() {
  //  if( instance == null ) instance = new LazySingleton();
  //}
}

根据Java的语言规范,上面的代码是不可靠的。
出现上述问题, 最重要的2个原因如下:
1, 编译器优化了程序指令, 以加快cpu处理速度.
2, 多核cpu动态调整指令顺序, 以加快并行运算能力.
问题出现的顺序:
1, 线程A, 发现对象未实例化, 准备开始实例化
2, 由于编译器优化了程序指令, 允许对象在构造函数未调用完前, 将 共享变量的引用指向 部分构造的对象, 虽然对象未完全实例化, 但已经不为null了.
3, 线程B, 发现部分构造的对象已不是null, 则直接返回了该对象.
不过, 一些著名的开源框架, 包括jive,lenya等也都在使用DCL模式, 且未见一些极端异常.
说明, DCL失效问题的出现率还是比较低的.



利用JAVA ClassLoader ,JRE自身特点,产生代码5.
(有兴趣的可以看看IBM和sun网写的java classLoader文章和有关类加载顺序)
代码5:
可以带父类的://会生成文件Singleton.class和Singleton$Instance.class
示例:
public class Singleton extends SuperSingleton {
  //内部类,将只被装载一次.
  private static class Instance {
    //final关键字
    static final SuperSingleton instance = new Singleton();
  }
  private Singleton() {
  }
  public static SuperSingleton getInstance() {
    return Instance.instance;
  }
  //暂未使用Singleton instance
  private static Singleton instance;
  public void doA() {
  }
  public void doB() {
  }

   //危险代码.
  protected void finalize(){
   //置空操作
  }
}
代码5是对于单线程或多线程都是可行的.
更符合类间关系的原则,对于对象A,A要么只创建B类,要么只使用B类的方法,不要二者兼之.
然后试试对代码5的使用感受吧.

注:另外针对从代码2到代码5,在ECLIPSE下是可以自己创建代码模板,供生成代码2到代码5.
在此不提供,让大家自己熟悉代码.
模板位置:eclipse->windows->preferrence->java->editors->templates->...
最后快捷键:ALT+/


参考资料:
1. book:  design pattern explains.
2. books and papers :  java memory model
3. java class loader
http://java.sun.com/developer/technicalArticles/Networking/classloaders/
http://download.oracle.com/javase/tutorial/ext/basics/load.html
http://www.ibm.com/developerworks/cn/java/j-lo-classloader/?ca=drs-tp4608
https://docs.google.com/viewer?a=v&q=cache:XhllCyQFTS0J:www.freejavaguide.com/jcl.pdf+java+classloader+ibm&hl=zh-CN&pid=bl&srcid=ADGEESiOaJjb2W-ilYRra4XOQEV4xbG1risXhRXdxtY0qYnhryvduOsLQapuQDdh1-A8frGy0cAqGNMV4vt8x-q_TLAoqgOKWpA1dlbn-6l_Jm3z2I6AvOLiXCztNafc_dx72C1hLzz0&sig=AHIEtbStlkg0vB89MsPd_YQQgHnpcrKn7A&pli=1