揭秘设计模式:单例模式(Singleton)的深入理解

    链接地址:http://www.xx566.com/detail/112.html

    前段时间在读Effective Java的时候,对单例(Singleton)模式的三种实现方式做过一点总结,不过当时也是一知半解,对其内部以及为什么这么设计并没有深入的理解,最 近在工作中又接触到了单例模式,有空又翻阅了一些设计模式的书籍,于是想重新做一下整理和理解。

    单例模式可能是众多设计模式中,类设计最简单的模式,不过它的作用却非常重要,在实现上也要许多需要注意的地方,首先, 单例模式的实现目前来看有三种方式:饿汉式、懒汉式和枚举式(具体内容请点击:三种方式实现类的Singleton(单例)),不过上次总结的时候,没有深入的研究,也没有考虑多线程并发之类的问题,这次在总结过程中,会特别注意一下。

    以下是实现单例的三种方式,我们来看一下,饿汉式单例实现,代码如下:

package javase.singleton;
 
/**
 * 饿汉式单例
 * 
 * @author Realfighter
 * 
 */
public class SingletonStarving {
 
    private static final SingletonStarving INSTANCE = new SingletonStarving();
 
    private SingletonStarving() {
    }
 
    public static SingletonStarving getInstance() {
        return INSTANCE;
    }
 
}

    懒汉式单例实现,代码如下:

package javase.singleton;
 
/**
 * 懒汉式单例
 * 
 * @author Realfighter
 * 
 */
public class SingletonIdler {
 
    private static SingletonIdler INSTANCE = null;
 
    private SingletonIdler() {
    }
 
    public synchronized static SingletonIdler getInstance() {
        if (INSTANCE == null) {
            INSTANCE = new SingletonIdler();
        }
        return INSTANCE;
    }
 
}

    以上实现方式中,懒汉式是比较特殊的,存在多线程并发的问题,所以需要synchronized关键字来确保同步,不过同步对资源性能损耗严 重,getInstance方法耗时严重,为了解决此问题,这里有一个Double-Checked Locking(双重检查加锁)的概念,这是我忽略的一个概念,来减少时间的耗费,示例代码如下:

package javase.singleton;
 
public class SingletonDoubleChecked {
    private static SingletonDoubleChecked INSTANCE = null;
 
    private SingletonDoubleChecked() {
    }
 
    public static SingletonDoubleChecked getInstance() {
        if (INSTANCE == null) {
            //检查实例,如果为空,就进入同步区域
            synchronized (SingletonDoubleChecked.class) {
                //进入同步区域后,再检查一次,如果仍为空,才创建实例
                if (INSTANCE == null) {
                    INSTANCE = new SingletonDoubleChecked();
                }
            }
        }
        return INSTANCE;
    }
}

    不过即便如此,依然无法保证返回唯一实例对象,这是由于在Java编译器中,类的初始化与INSTANCE变量的赋值顺序不可预料,如果一个线程在没有同 步化的条件下读取INSTANCE的引用,并调用这个对象的方法,可能对象的初始化过程尚未完成,从而造成崩溃,不过这种问题也有解决方法,我们可以通过 类加载器机制,代码如下:

package javase.singleton;
 
/**
 * 类加载器机制解决双重检查加锁问题 
 * 内部类Instance只被装载一次,
 * 保证对象SingletonDoubleCheckedByClassLoader只有一个
 * 
 * @author Realfighter
 * 
 */
public class SingletonDoubleCheckedByClassLoader {
 
    private static class Instance {
        static final SingletonDoubleCheckedByClassLoader instance = new SingletonDoubleCheckedByClassLoader();
    }
 
    private SingletonDoubleCheckedByClassLoader() {
    }
 
    public static SingletonDoubleCheckedByClassLoader getInstance() {
        return Instance.instance;
    }
}

    我们也可以利用volatile关键字解决,代码如下:  

package javase.singleton;
 
/**
 * volatile关键字保证,
 * INSTANCE变量被初始化为Singleton实例时,
 * 多个线程能正确的处理INSTANCE变量
 * 
 * @author Realfighter
 * 
 */
public class SingletonDoubleCheckedByVolatile {
 
    private volatile static SingletonDoubleCheckedByVolatile INSTANCE = null;
 
    private SingletonDoubleCheckedByVolatile() {
    }
 
    public static SingletonDoubleCheckedByVolatile getInstance() {
        if (INSTANCE == null) {
            synchronized (SingletonDoubleCheckedByVolatile.class) {
                if (INSTANCE == null) {
                    INSTANCE = new SingletonDoubleCheckedByVolatile();
                }
            }
        }
        return INSTANCE;
    }
}

    JDK1.5,提出了一种新特性:enum枚举,通过enum枚举实现单例非常的简单,而且在枚举里面创建实例也是线程安全的,是强烈推荐使用的,代码如下:

package javase.singleton;
 
/**
 * 枚举实现单例
 * @author Realfighter
 *
 */
public enum SingletonEnum {
    INSTANCE;
}

    我们只需要使用SingletonEnum.INSTANCE就可以获取它的唯一实例了,总的来说,单例模式是众多设计模式中比较简单的一个,也是很重要的一种模式,在工作中的某些需求中也有可能会经常用到,还是需要好好学习哈。

你可能感兴趣的:(java,设计模式,单例模式,Singleton,三种)