java单例模式总结

java单例模式应用非常广泛,主要目的都是确保一个对象实例在整个应用中只会创建一次。实现单例的方式有以下几种,他们主要的区别在于是否线程安全,是否实现延迟加载,是否影响程序性能等等。

非线程安全的懒汉模式

public class LazySingleton {

    private static LazySingleton instance;

    private LazySingleton(){

    }

    public static LazySingleton getInstance(){
        if(null == instance){  //--------------------(1)
            instance = new LazySingleton();
        }
        return instance;
    }
}

之所以称之为懒汉模式,是因为这种模式有明显的延迟加载,只有在第一次调用getInstance方法时,才会实例化单例对象。在多线程场景下,若两个线程同时到达(1)代码处,此时实例为空,就会创建了两个LazySingleton对象,(实际上先创建的对象会被后创建的对象覆盖)。

线程安全的懒汉模式

public class LazySingletonSafe {

    private static LazySingletonSafe instance;

    private LazySingletonSafe(){

    }

    public static synchronized LazySingletonSafe getInstance(){
        if(null == instance){
            instance = new LazySingletonSafe();
        }
        return instance;
    }
}

与非线程安全懒汉模式相比,线程安全模式通过synchronized关键字实现竞争锁达到线程安全的目的。这种模式每次都要去获取锁,操作比较重,影响性能,不推荐。

饿汉模式

public class HungrySingleton {
    
    private static HungrySingleton instance = new HungrySingleton();

    private HungrySingleton(){}

    public static HungrySingleton getInstance(){
        return instance;
    }
}

饿汉模式通过static静态变量内存常驻的特点实现单例,缺点是在类加载时即实例化单例对象,没有实现延迟加载,可能会导致占用系统资源导致资源浪费。

内部类单例模式

public class InnerSingleton {

    private static class InnerSingletonHolder{
        private static InnerSingleton instance = new InnerSingleton();
    }

    private InnerSingleton(){}

    public static InnerSingleton getInstance(){
        return InnerSingletonHolder.instance;
    }
}

静态内部类实现单例模式的好处是,不会在加载时就实例化单例对象,而是在调用getInstance方法时才实例化单例对象。由于静态内部类只有被调用时才会加载,所以这种方式实现了延迟加载,同时保证线程安全。

双重校验锁单例模式

public class DoubleCheckSingleton {

    private static DoubleCheckSingleton instance;

    private DoubleCheckSingleton(){}

    public static DoubleCheckSingleton getInstance(){
        //只有实例为null时,才去竞争锁
        if(null == instance){
            synchronized (DoubleCheckSingleton.class){
                //获得锁之后,第二次校验实例是否已被其他先获得锁的线程创建了
                if(null == instance){
                    instance = new DoubleCheckSingleton();
                }
            }
        }
        return instance;
    }
}

双重校验锁单例模式是对懒汉模式的改良,只有单例还未实例化时才去竞争锁,而不用每次都要竞争锁。理论上这种实现方式是线程安全的,因为java编译器会把字节码命令重排序,在java虚拟机内部,完全有可能先new出来一个空的未调用过构造函数的instance对象,然后再将其赋值给instance引用,然后再调用构造函数,对instance对象当中的元素进行初始化。这样,就很有可能,当instance被赋值一个空的实例对象的时候,另一个线程调用了getInstance()这个函数,另一个线程发现,instance并不是空的,于是愉快地return回了那个空的instance对象。这样,一个空的instance对象的引用就被流传到了其他线程当中,为非作歹。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值