饿汉式是没有线程安全问题的,下面主要说下懒汉式的安全模式
一、double check
package Singleton;
/**
* 类描述:test
*/
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;
}
}
一般的double check是会有线程安全问题的,这是因为对象的创建有3个步骤:
1、给对象分配内存空间
2、初始化对象
3、将引用instance指向分配的内存空间
由于jvm和cpu可能进行优化而进行重排序,这样的话第2和3步交换顺序,在执行到第3步时恰巧判断了instance是否为null,这个时候就会返回一个没有初始化完成的install对象,这是有问题的
所以在这里的instace加上了关键字volatile修饰,根据jmm的规则保证了初始化对象的顺序,所以线程安全问题解决
二、枚举方式(推荐)
package Singleton;
/**
* 类描述:test
*/
public class SingletonEnum {
private SingletonEnum() {}
public static SingletonEnum getInstance() {
return Singleton.INSTANCE.getInstance();
}
private enum Singleton {
INSTANCE;
private SingletonEnum instance;
Singleton() {
instance = new SingletonEnum();
}
public SingletonEnum getInstance() {
return instance;
}
}
}
这个是通过利用枚举的特性,JVM会保证枚举的构造函数只会调用一次,所以肯定是线程安全的,另外这里起到了资源的合理利用,只有在真正用到实例的时候采取初始化对象了