SEARU.ORG
当前位置:SEARU.ORG > Linux 教程 > 正文

Java设计模式-单例模式

相信大家去面试的时候,经常被问到单例模式的有关问题吧,今天我们就来好好总结一下
一 懒汉式

public class Singleton {  
    private static Singleton instance = null;  
    private Singleton() {}  
    public static Singleton getInstance() {  

        if (instance == null) {   
            instance = new Singleton();   
        }  
        return instance;  
    }  
}

相信大家对这段代码再熟悉不过了,懒汉式的意思就是每次在调用getInstance方法时,才去new一个Singleton的实例,但是很明显,按上面这样写有问题啊,线程不同步啊,那么怎么办呢

public class Singleton {  
    private static Singleton instance = null;  
    private Singleton() {}  
    public static synchronized  Singleton getInstance() {  

        if (instance == null) {   
            instance = new Singleton();   
        }  
        return instance;  
    }  
}  

在getInstance方法之前加上synchronized不就解决了,但是这样,每次调用getInstance都会同步,而我们只是希望在第一次new Singleton()的时候同步即可,一旦instance不为空了,就不用再同步了,那么怎么做呢

public class Singleton {  

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

在代码块利用锁,并且要加上双重检测,因为两个线程很可能同时执行到第一个判空的地方,可能判断都为空,就都会进入下面的代码里,就会生成两个对象,所以要加上双重锁定,但是这样就没问题了吗,当然不是,我们都知道java内存模型中有无序写的机制,instance = new Singleton(); 这行其实做了两个事情:1、调用构造方法,创建了一个实例。2、把这个实例赋值给instance这个实例变量。可问题就是,这两步jvm是不保证顺序的。也就是说。可能在调用构造方法之前,instance已经被设置为非空了
比如顺序被重排了,先保证instance 不为null,后面才调用构造函数初始化,这个时候另外一个线程判断instance 不为空,直接返回instance ,这样就会有问题,那么怎么解决这个问题呢,我们知道 volatile关键字可以在instance 赋值的时候,禁止重排序

public class Singleton {
    private volatile static Singleton instance; //声明成 volatile
    private Singleton (){}

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

这样这个问题就解决了,但是是不是觉得很累,下面给出一种完美的解决方法,利用静态内部类

public class Singleton {  

    private static class SingletonHolder{  
        private static Singleton instance = new Singleton();  
    }  

    private Singleton() {  
    }  

    //获取单例对象实例  
    public static Singleton getInstance() {  
        return SingletonHolder.instance;  
    }  
}  

我们知道,静态内部类只有在getInstance里第一次被调用的时候才加载,实现了懒加载,而且加载过程是线程安全的,所以一般用这种方法来实现懒汉式单例子

二 饿汉式

//饿汉式  
public class Singleton {  
    private static Singleton instance = new Singleton();       
    private Singleton() {}  
    public static Singleton getInstance() {  
        return instance;  
    }  
}  

在类加载的时候就new好对象,这样也不存在线程安全问题,但是饿汉式也有问题,如果构造的单例很大,构造完又迟迟不使用,会导致资源浪费。

总结:推荐使用懒汉式静态内部类的方式实现单例模式,好了,设计模式-单例模式就总结到这里,如有问题,欢迎指正,谢谢。

未经允许不得转载:SEARU.ORG » Java设计模式-单例模式

赞 (0)
分享到:更多 ()

评论 0