何为单例模式?
通常点说就是一个类只有一个实例,这意味着其构造函数是私有的。
这里让我想到了spring ioc管理的bean,默认也是单例的。不过这里的概念跟设计模式里的单例不一样,ioc里的bean被设计成单例
在于为了servlet容器初始化spring容器时降低内存开销。
spring ioc还有个关注点:被注入的bean可以是原生对象,也可以是被aop增强的代理对象(也就是说在ioc容器里的原生对象并不对外提供服务)。
单线程下的单例
单例代码一(懒汉模式),性能比饿汉的好一些 懒加载思想很多地方都用到,比如spring 、dubboz中@Reference(lazy=true)
public class Singleton {
private static Singleton singleton = null;//懒汉=先不创建实例
private Singleton(){
}
public static Singleton getInstance() {
if(null == singleton) {
singleton = new Singleton();
}
return singleton;
}
}
此为最基本的。
单例代码二 (饿汉模式)
public class Singleton{
private static final Singleton singleton = new Singleton();//饿汉
//介绍一种变种的写法
/*private static Singleton singleton = null;
static{
singleton = new Singleton();
}
*/
private Singleton() {
}
public static Singleton getInstance() {
return singleton;
}
}
以上两段代码在单线程下没啥问题,但是多线程就不行了。
引入两个线程:A和B.
当A线程进入代码一getInstance方法,刚判断对象为null,此时cpu切换到线程二执行,然后B检测到也为null然后创建对象,过程结束后cpu切换到A继续(因为A之前检测为null)所以直接创建实例了。最终得到两个实例,违反了单例原则。
继续优化实现饿汉式,接下来加入了懒加载思想
public class Singleton{
private static class SingletonHolder{
private static final Singleton singleton = new Singleton();
}
private Singleton() {
}
public Singleton getInstance() {
return SingletonHolder.singleton;
}
}
对比之前饿汉式,都是由Singleton类装载时就初始化好了实例,而现在只有当执行getInstance方法才会去内部类获取到实例,所以延迟了事先获取实例体现了懒加载思想。
多线程下的单例
单例代码三(以下只对懒汉的研究,饿汉性能差就算了)
public class Singleton{
private static Singleton singleton = null;
private Singleton() {
}
public static synchronized Singleton getInstance() {
if(null == singleton) {
singleton = new Singleton();
}
return singleton;
}
}
该段代码以同步方式实现了了线程安全,由于是在方法上加synchronized,所以一旦线程多了就阻塞等待很长时间,所以性能也偏抵。
对以上代码进行调优:
public class Singleton{
private static Singleton singleton = null;
private Singleton() {
}
public static Singleton getInstance() {
if(null == singleton) {//这个也很重要
synchronized(Singleton.class) {
if(null == singleton){//这个很重要
singleton = new Singleton();
}
}
}
return singleton;
}
}
该代码通过先判断对象是否null,若为null则A线程获取锁B线程也等待,A执行完轮到B(此时对象已经不为null了),此时B进入代码块后又判断是否为null,结果不是,最终也返回对象。这边两个null判断是关键。这个完美实现了
思想在于:double---checked----locking 。