现在的位置: 首页 > 综合 > 正文

【设计模式】学习笔记7:单件模式(Singleton)

2013年08月01日 ⁄ 综合 ⁄ 共 1982字 ⁄ 字号 评论关闭
文章目录

本文出自   http://blog.csdn.net/shuangde800

走进单件模式

有些对象我们只需要一个,比如:线程池,缓存,对话框,处理偏好设置和注册表的对象,日志对象,充当打印机,显卡等设备的驱动程序对象等。

这些类的对象只能有一个实例,如果有多个,然而会导致许多问题产生。

有人可能觉得,这只要用全局变量或者静态变量就可以做到了

这样做的缺点:

必须程序一开始就创建对象,但是有些对象可能用不到,耗费资源。而单件模式在需要时才创建

单间模式的实现


单件模式的经典但简陋(有问题)的实现:

把构造函数设置为私有的,再加一个静态方法用来创建对象并返回。

public Singleton{
    
    private static Sigleton uniqueInstance;

    // 构造器是私有的,只有类内部方法才能创建类
    private Singleton() { }

    public static MyClass getInstance(){
        if(uniqueInstance == null){ // 只有是null的才创建对象
            uniqueInstance = new Singleton(); 
        }
        return uniqueInstance;
    }
}


上面那个做法,会出现问题,原因是多线程产生的问题。

假如有两个线程要几乎同时要创建一个对象,那么将会发生下面的情况:

看上图,发现Thread one和Thread two都各自创建了一个对象!

 解决方案1

把getInstance( )变成同步(synchronized)方法,多线程灾难几乎就可以轻易解决了。

public Singleton{
    
    private static Sigleton uniqueInstance;

    // 构造器是私有的,只有类内部方法才能创建类
    private Singleton() { }

    // 通过增加synchronized关键字,会迫使每个线程在进入这个
    // 方法之前,要先等候别的线程离开该方法。
    // 也就是说,不会有两个线程可以同时进入这个方法
    public static synchronized MyClass getInstance(){
        if(uniqueInstance == null){ // 只有是null的才创建对象
            uniqueInstance = new Singleton(); 
        }
        return uniqueInstance;
    }
}


缺点: 每次用该方法都要同步,会降低拖垮程序的性能。同步一个方法可能会造成程序执行效率下降100倍。


解决方案2:急切实例化

public Singleton{
    
    // 在静态初始化器(static initializer)中创建单件
    // 保证了线程安全(thread safe)
    private static Sigleton uniqueInstance = new Singleton();

    // 构造器是私有的,只有类内部方法才能创建类
    private Singleton() { }

    public static synchronized MyClass getInstance(){
        return uniqueInstance;
    }
}

解决方案3: 用“双重检查加锁”,在getInstance()中减少使用同步

利用“双重检查加锁”(double-checked locking),首先检查实例是否已经创建了,如果尚未创建,“才”进行同步。

这样,只有第一次会同步,之后再也不会了

public Singleton{

    // 注意这里加了volatile关键字
    // volatile关键字确保:当uniqueInstance变量被初始化成Singleton实例时
    // 多个线程正确地处理uniqueInstance变量
    private static volatile Sigleton uniqueInstance;

    private Singleton() { }

    public static synchronized MyClass getInstance() {
        if(uniqueInstance == null) { 
            synchronized (Singleton.class) {
                if(uniqueInstance == null){
                    uniqueInstance = new Singleton(); 
                } 
            }
        }
        return uniqueInstance;
    }
}

注意! 双重检查加锁不使用于java 1.4以及更早的版本。

定义单件模式

单件模式确保一个类只有一个实例,并提供一个全局访问点

单件模式的类图很简单

全局变量 VS 单件模式

在Java中,全局变量基本上就是对对象的静态引用。

在这样的情况下使用全局变量会有一些缺点,我们已经提到了期中一个:急切实例化 VS.延迟实例化。

但是我们要记住这个模式的目的:确保类只有一个实例并提供全局访问。

全局变量也会变相鼓励开发人员,用许多全局变量指向许多小对象来造成命名空间(namespace)的污染。

单件模式不鼓励这样的现象,但单件仍然可能被滥用。

抱歉!评论已关闭.