单例模式的几种创建方法(synchorized、DoubleCheck、静态内部类等)

单例模式

单例模式是创建型模式,它确保了一个类只能有一个对象被创建。

在单例模式中,需要注意以下几点:

  • 构造方法必须为private,不能被其他类调用new方法
  • 成员变量为static的,这样子才能被static方法返回

饿汉式

饿汉式在类加载的时候就被初始化,免去检查是否为空的步骤,但是如果一直没有被调用的话,就会造成浪费。

public class HungrySingleton {
    private static HungrySingleton hungrySingleton = new HungrySingleton();
    
    private HungrySingleton(){
        
    }
    
    public static HungrySingleton getInstance(){
        return hungrySingleton;
    }
}

懒汉式

如下为懒汉单例模式的一个实例,他会在需要调用的时候才实行new初始化,为延迟加载的一个方法。但是这个方法是线程不安全的,如果有大量线程在初始化之前同时调用getInstance(),会导致new方法被调用多次,产生大量重复对象。

//懒汉单例模式
public class LazySingleton {
    private static LazySingleton lazySingleton;

    private LazySingleton(){

    }


    public static LazySingleton getInstance(){
        if(lazySingleton==null){
            lazySingleton=  new LazySingleton();
        }
        return lazySingleton;
    }
    
}

Synchronized

为了让单例模式可以实现线程安全,我们可以利用synchronized修饰getInstance()方法。其中getInstance1()和getInstance2()效果是一样的,因为synchronized 修饰的是static方法,所以它也会锁住这个类


//懒汉单例模式
public class LazySingleton {
    private static LazySingleton lazySingleton;

    private LazySingleton(){

    }


    public static synchronized LazySingleton getInstance1(){
        
        if(lazySingleton==null){
            lazySingleton=  new LazySingleton();
        }
        return lazySingleton;
    }

    public static LazySingleton getInstance2(){
        synchronized (LazySingleton.class){
            if(lazySingleton==null){
                lazySingleton=  new LazySingleton();
            }
        }
        return lazySingleton;
    }
}

DoubleCheck

但是使用synchronized的效率并不高,我们可以利用双重检查double check的方法来创建单例模式

public class LazySingletonDoubleCheck {
    private volatile static LazySingletonDoubleCheck lazySingletonDoubleCheck;

    private LazySingletonDoubleCheck(){

    }

    public static LazySingletonDoubleCheck getInstance(){
        if(lazySingletonDoubleCheck==null){
            synchronized (LazySingletonDoubleCheck.class){
                if(lazySingletonDoubleCheck==null){
                    lazySingletonDoubleCheck = new LazySingletonDoubleCheck();
					//1.为对象分配内存
                    //2.调用构造方法初始化
                    //3.将对象的指针指向内存
                }

            }

        }
        return lazySingletonDoubleCheck;
        
    }
}

因为之前的synchronized修饰的是getInstance()方法,即使对象已经初始化完成来,仍然需要上锁,效率很低。所以DoubleCheck把synchronized锁放到了判断对象为空之后。

这种需要重点注意的是,在lazySingletonDoubleCheck = new LazySingletonDoubleCheck();这一句中,涉及三个步骤:
第一步,为对象分配内存
第二步,调用构造方法初始化
第三步,将对象的指针指向内存

因为编译器的优化,其中第二步和第三步可能会重排序,导致顺序变成

1.为对象分配内存
2.将对象的指针指向内存
3.调用构造方法初始化

所以可能会出现以下情况:
在这里插入图片描述

所以我们需要给对象加上volatile关键词,让这个对象禁止重排序

静态内部类

可以使用静态内部类的方法构造,静态内部类相当于一个静态属性,只有在第一次加载类时才会初始化,在类初始化时,别的线程是无法进入的,因此保证了线程安全。

public class LazySingletonStaticInnerClass {
    private LazySingletonStaticInnerClass(){
        
    }

    private static class InnerClassHolder{
        private static LazySingletonStaticInnerClass lazySingletonStaticInnerClass = new LazySingletonStaticInnerClass();
    }
    
    public static LazySingletonStaticInnerClass getInstance(){
        return InnerClassHolder.lazySingletonStaticInnerClass;
    }

}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值