JAVA实现单例模式
JAVA实现单例模式主要有:懒汉、饿汉、双重检验锁、静态内部类和枚举几种方式。
一、懒汉,线程不安全
public class Singleton {
private static Singleton instance;
private Singleton (){}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
这种方式之所以线程不安全是因为当多个线程同时使用getInstance()方法时,可能产生多个实例。
二、懒汉,线程安全
public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; }
加上synchronized关键字后,保证了线程安全,但是任何时候只能有一个线程调用getInstance()方法,所以并不高效。
三、饿汉
public class Singleton{
//类加载时就初始化
private static final Singleton instance = new Singleton();
private Singleton(){}
public static Singleton getInstance(){
return 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;
}
}
这里有两点要注意,一是两次检验instance==null,因为可能有多个线程同时进入外面的if,如果没有内部if检查,会创建多个实例。二是volatile关键字。因为instance=new Singleton()分三步进行:
1) 给instance分配内存;
2)调用Singleton构造函数初始化成员变量;
3)将instance对象指向内存空间。
由于JVM编译器中存在指令排序的优化,也就是说2)和3)的顺序是不能保证的。设想一下,如果执行顺序是1,3,2,在执行完3之后,然后被线程二占用,这时instance已经是非null,线程二直接返回instance,这样在使用时就会报错。
volatile的作用在于禁止指令重排序优化。
五、静态内部类
public class Singleton {
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton (){}
public static final Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
这也是一种”懒汉”的方式,把实例化推迟到使用getInstance()方法之后。
六、枚举
public enum EasySingleton{
INSTANCE;
}
可见枚举类型是最简单的一种方法。
浙公网安备 33010602011771号