二学单例模式

二学单例模式

哎呀!单例都学烂了,有什么好学的啊?

因为今天看《Head First 设计模式》看到了一些细节部分,决定重新认识一下单例

应用场景

  • 线程池
  • 缓存
  • 注册表
  • 工厂
  • 对话框
  • 偏好设置

普通的单例

我们先来看看

public Single{
    private static Single singleInstance;
	private Single(){}
    public static Single getSingleInstance(){
        if(singleInstance == null){
            singleInstance = new Single();
        }
        return singleInstance;
    }
}

很简单的一个例子,大家都会写,把构造隐藏起来,把方法暴露出去,blablabla…

但是这涉及到多线程的话,如果我两个线程同时到达if(singleInstance == null),怎么办,这就会出来两个不同的对象啊,这是不安全的,那怎么办呢?

线程安全性

处理多线程问题,我们有三种方法

方法一:提前new好

别嫌代码臭嗷~

public Single{
    private static Single singleInstance = new Single();
	private Single(){}
    public static Single getSingleInstance(){
        return singleInstance;
    }
}

JVM加载这个类时,马上就会创建好这个对象。如果在创建和运行方面压力不大,你又急着用,确实可以这么做

方法二:增加同步(synchronized)块

还记得synchronized吗?

public Single{
    private static Single singleInstance;
	private Single(){}
    public static synchronized Single getSingleInstance(){
        if(singleInstance == null){
            singleInstance = new Single();
        }
        return singleInstance;
    }
}

在方法中间加上synchronized关键字,问题解决了,但如果我对象都已经创建好了了,我直接拿不久行了,也搁哪儿等着?所以,随之而来的是性能的灾难…(可能差几十倍甚至一百倍)

方法三:减少同步,使用双重锁DCL(Double-Checked Lock)

先检查单例对象创建了没,没创建再同步,而不是不管三七二十一,全同步了

public Single{
    private volatile static Single singleInstance;
	private Single(){}
    public static Single getSingleInstance(){
        if(singleInstance == null){
            synchronized(Single.class){
                if(singleInstance == null){
                    singleInstance = new Single();
                }
            }          
        }
        return singleInstance;
    }
}

利用双重锁机制,性能

单例 vs 全局变量

还记得我“二学static”里面的例子吗?

//Code.1
public Single{
    static public void FuncA(Object o);
    static public void FuncB(Object o);
    static public void FuncC(Object o);
}

// Code.2
public Single{
    private static Single singleInstance;
	private Single(){}
    public static Single getSingleInstance(){
        if(singleInstance == null){
            singleInstance = new Single();
        }
        return singleInstance;
    }
    public void FuncA(Object o);
    public void FuncB(Object o);
    public void FuncC(Object o);
}

// 分别调用FuncA
Object o = new Object();
// call 1
Single.FuncA(o);
// call 2
Single.getSingleInstance().FuncA(o);

除了我之前文章说的不同,还存在初始化的和控制权不同的问题

初始化

  • 单例延迟初始化
  • 类加载后的初始化时间在Java程序

控制权

  • 单例控制权在我们
  • 全局变量控制权在Java

你可能感兴趣的:(程序设计思想)