版权声明:本文为作者的原创文章,未经允许不得转载。 https://blog.csdn.net/lele1658676840/article/details/82416164
文章目录
1. 饿汉式(线程安全)
public static class Singleton{
private final static Singleton INSTANCE = new Singleton();
private Singleton{
}
public static Singleton getInstance(){
return INSTANCE;
}
}
饿汉模式在类被初始化时就已经在内存中创建了对象,以空间换时间,故不存在线程安全问题。
2. 懒汉式(线程不安全)
public static class Singleton{
private static Singleton INSTANCE = null;
private Singleton{
}
public static Singleton getInstance(){
if(INSTANCE == null){
INSTANCE = new Singleton();
}
return INSTANCE;
}
}
懒汉模式在方法被调用后才创建对象,以时间换空间,在多线程环境下存在风险。
3. 懒汉式(线程安全,多线程下效率不高)
public static class Singleton{
private static Singleton INSTANCE = null;
private Singleton{
}
public static synchronized Singleton getInstance(){
if(INSTANCE == null){
INSTANCE = new Singleton();
}
return INSTANCE;
}
}
4. 懒汉式(线程安全)
public static class Singleton{
private static Singleton INSTANCE = null;
static{
INSTANCE = new Singleton();
}
private Singleton{
}
public static Singleton getInstance(){
return INSTANCE;
}
}
5. 双重锁懒汉式(线程安全)
public static class Singleton{
private volatile static Singleton INSTANCE = null;
private Singleton{
}
public static Singleton getInstance(){
if(INSTANCE == null){
synchnronized(Singleton.class){
if(INSTANCE == null){
INSTANCE = new Singleton();
}
}
}
return INSTANCE;
}
}
DCL模式的优点就是,只有在对象需要被使用时才创建,第一次判断 INSTANCE == null为了避免非必要加锁,当第一次加载时才对实例进行加锁再实例化。这样既可以节约内存空间,又可以保证线程安全。但是,由于jvm存在乱序执行功能,DCL也会出现线程不安全的情况。具体分析如下:
INSTANCE = new SingleTon();
这个步骤,其实在jvm里面的执行分为三步:
1.在堆内存开辟内存空间。
2.在堆内存中实例化SingleTon里面的各个参数。
3.把对象指向堆内存空间。
由于jvm存在乱序执行功能,所以可能在2还没执行时就先执行了3,如果此时再被切换到该线程上,由于执行了3,INSTANCE 已经非空了,会被直接拿出来用,这样的话,就会出现异常。这个就是著名的DCL失效问题。
不过在JDK1.5之后,官方也发现了这个问题,故而具体化了volatile,即在JDK1.6及以后,只要定义为private volatile static SingleTon INSTANCE = null;就可解决DCL失效问题。volatile确保INSTANCE每次均在主内存中读取,这样虽然会牺牲一点效率,但也无伤大雅。
6. 静态内部类(线程安全,推荐)
public static class Singleton{
private final static class SingletonHolder{
private final static Singleton INSTANCE = new Singleton();
}
private Singleton{
}
public static Singleton getInstance(){
return SingletonHolder.INSTANCE;
}
}