单例模式的改进

  前面说过的单例模式为了避免被不同的线程创建多次,各个线程引用了不同的实例,这违背了我们的“唯一实例”的初衷,因此,我们采取了同步的机制(

synchronized 

),代码如下:

public class Singleton {
    private static Singleton single = null;
    
    private Singleton() {
        System.out.println("create a singleton class.");
    }
    
    public synchronized static Singleton getInstance() {
        if(null == single) {
            single = new Singleton();
        }
        return single;
    }
    
    public void dosth() {
        System.out.println("do somethings.");
    }

}

public static void main(String[] args) {
        // TODO Auto-generated method stub
        Singleton single = Singleton.getInstance();
        single.dosth();
    }

  但是这样带来了一个新的问题:性能问题。每次访问getInstance都需要进行同步。事实上,我们只需在构造第一个也是唯一一个Singleton类实例的时候进行同步

  我们采用一个Double Check的方式修正上面的代码。

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

  Double Check方式改进:

  • 虽然是多线程环境,但如果没有外层if,客户程序每次执行时都要先synchronized为Singleton类型,但是在绝大多数情况下,每次锁定synchronized类型效率太低,这个锁定很可能就成了整个应用的瓶颈。
  • synchronized加内层的if 组成了一个相对线程安全的实例构造环境。

  虽然看起来Double Check方式很完美,但事实上这个方案还是存在问题:多线程环境下不能确保singleton == null操作的原子性。

 

  修改后的Double Check方式代码:

public class Singleton {

    private static volatile Singleton singleton = null;
    private Singleton()
    {
        
    }
    
    public static Singleton getInstance() {
        if(singleton == null) {
            synchronized(Singleton.class) {
                if(singleton == null) {
                    singleton = new Singleton();
                }
            }
        }
        return singleton;
    }
}

 

 

posted @ 2013-11-14 17:01  wiessharling  阅读(347)  评论(0编辑  收藏  举报