最近闲来捣腾下安卓,看到一个关于java单例的讲解,真是TM万幸前端的javascript是单线程的,原来java的单例为了多线程,也能搞出一堆花出来,这里是文章探索设计模式之六——单例模式

来,先看看javascript怎么实现类式面向对象的单例的:

'use strict';  
var MyDearSingleton = (function () {  
    // 通过匿名执行的函数所创造的作用域,对外形成不可访问性,模拟__instance私有变量
    var __instance = null; 
    // 定义一个单例类MyDearSingleton
    var MyDearSingleton = function () {
        // 即使使用new关键字,也要返回单例对象
        if (__instance) {
            return __instance;
        }
        __instance = this;
    };
    // 实现静态方法getInstance
    MyDearSingleton.getInstance = function () {
        if (null === __instance) {
            __instance = new this();
        }
        return __instance;
    };
    // 类的实例方法定义
    MyDearSingleton.prototype = {
        // 修正constructor属性
        constructor: MyDearSingleton,
        doSomething: function () { ... }
    };
    return MyDearSingleton;
})();

// Main ...
MyDearSingleton.getInstance().doSomething();  

我们看到getInstance的实现方式

MyDearSingleton.getInstance = function () {  
    if (null === __instance) {
          __instance = new this();
    }
    return __instance;
};

在js终生单线程的的前提下,任何代码片段是终生同步的,instance永远最多只有一个实例运行在内存。

这里java,我们知道,要使用单例的时候,一般是需要推迟实例化的,今天倒是看到两个新名词,“恶汉”、“懒汉”(可惜没有找到“痴汉” :<)

按照他的说法,上述的脚本,理应算作“痴汉”...... 哦,不好意思说错,是“懒汉”。什么是“恶汉”?就是很直接地和类一起来到这个世界,类加载,即我存在,类似于盘古开天辟地那种。个人感觉,使用恶汉的唯一理由是为了直接了当地解决并发。

换成js,也就是说instance在我们类定义的时候,就直接给你实例化好了

'use strict';  
var MyDearSingleton = (function () {  
    // 通过匿名执行的函数所创造的作用域,对外形成不可访问性,模拟__instance私有变量
    var __instance = null; 
    // 定义一个单例类MyDearSingleton
    var MyDearSingleton = function () {
    };
    // 实现静态方法getInstance
    MyDearSingleton.getInstance = function () {
        return __instance;
    };
    // 类的实例方法定义
    MyDearSingleton.prototype = {
        // 修正constructor属性
        constructor: MyDearSingleton,
        doSomething: function () { ... }
    };

    // 直接实例化就好,因为我是“恶汉”!
    __instance = new MyDearSingleton();

    return MyDearSingleton;
})();

// Main ...
MyDearSingleton.getInstance().doSomething();  

我们看看贴过来的代码

/** 
 * 实现单例访问Kerrigan的第六次尝试 
 */  
public class SingletonKerriganF {  

    private static class SingletonHolder {  
        /** 
         * 单例对象实例 
         */  
        static final SingletonKerriganF INSTANCE = new SingletonKerriganF();  
    }  

    public static SingletonKerriganF getInstance() {  
        return SingletonHolder.INSTANCE;  
    }  
} 

咋一看,以为这种java写法很奇葩,不就是“恶汉”么,但是回想一下传说中的“静态内部类”,静态类是伴随着类的第一次引用才会被初始化的!也就是说,巧妙地利用静态内部类的本身特性,在不使用任何多线程语法关键字的前提下,保证了两点:

  • 单例的延迟初始化,解决在应用程序不需要单例的前提下,降低程序资源消耗;
  • 单例的延迟初始化是线程安全的,用到了jvm的底层特性;