单例模式
定义:Ensure a class has only one instance, and provide a global point of access to it. (确保一个类只有一个实例,并提供一个全局访问点来访问这个唯一实例。)
优势:通过使用 private 的构造函数确保在一个 application 中只产生一个实例,从而减少内存开支,特别是一个对象需要被频繁的创建和销毁时。
单例模式的5种实现方式:
1、懒汉式(要别人叫才吃饭,吃饭不积极脑子有问题)
public class Singleton{
private static Singleton instance=null;
private Singleton(){
}
public static synchronized Singleton getInstance(){
if(instance==null){
instance=new Singleton;
}
return instance;
}
}
2、饿汉式(人家还没叫你吃饭你就开始吃上了)
public class Singleton{
// initailzed during class loading
private static final Singleton instance = new Singleton();
//to prevent creating another instance of Singleton
private Singleton(){
//do something
}
public static Singleton getInstance(){
return instance;
}
}
复制代码
因为单例是静态的final变量,所以当类第一次加载到内存中的时候就初始化了,那么创建的实例固然是线程安全的。 |
3、静态内部类实现单例模式
public class Singleton {
public static class LazyHolder{
private static final Singleton INSTANCE = new Singleton();
}
private Singleton(){ }
public static Singleton getInstance(){
return LazyHolder.INSTANCE;
}
}
这里有几个需要注意的点:
1.从外部无法访问静态内部类LazyHolder,只有当调用Singleton.getInstance方法的时候,才能得到单例对象INSTANCE。
2.INSTANCE对象初始化的时机并不是在单例类Singleton被加载的时候,而是在调用getInstance方法,使得静态内部类LazyHolder被加载的时候。因此这种实现方式是利用classloader的加载机制来实现懒加载,并保证构建单例的线程安全。
3.静态内部类的实现方式也存在单例模式共同的问题:无法防止利用反射来重复构建对象
4、synchronized、volatile实现单例模式(双重锁)
public class Singleton {
private Singleton() {} //私有构造函数
private volatile static Singleton instance = null; //单例对象
//静态工厂方法
public static Singleton getInstance() {
if (instance == null) { //双重检测机制
synchronized (Singleton.class){ //同步锁
if (instance == null) { //双重检测机制
instance = new Singleton();
}
}
}
return instance;
}
}
经过volatile的修饰,当线程A执行instance = new Singleton的时候,JVM执行顺序是什么样?始终保证是下面的顺序:
memory =allocate(); //1:分配对象的内存空间
ctorInstance(memory); //2:初始化对象
instance =memory; //3:设置instance指向刚分配的内存地址
volatile关键字不但可以防止指令重排,也可以保证线程访问的变量值是主内存中的最新值。
如此在线程B看来,instance对象的引用要么指向null,要么指向一个初始化完毕的Instance,而不会出现某个中间态,保证了安全。
5、用枚举实现单例模式:
public enum SingletonEnum {
INSTANCE;
}
这种方法利用enum语法糖,JVM会阻止反射获取枚举类的私有构造方法。
评论