性价比超高的设计模式——单例模式

为什么说单例模式性价比高?
在面试过程中经常让手撸的一种设计模式,并且被面的频率非常高。重点是这种设计模式很简单!

我的个人博客(后台建站,Tomcat集群,Redis分布式,nginx,适合初学者)

为什么要用单例模式?

在开发过程中,根据需求的不同,有时可能要求对象实例只能有一个,这时就要使用到了单例模式。

如:Spring中的bean默认使用的都是单例模式。

什么是单例模式?

确保对象只有一个,并提供一个全局访问点。

一、单例模式初探

经典的实现方式:

饿汉式

public  class Singleton1{
    private static Singleton1 uniqueInstance = new Singleton1();
    private Singleton1() {
        super();
    }
    
    public static Singleton1 getInstance(){
        return uniqueInstance;
    }
}

懒汉式

public  class Singleton2{
    private static Singleton2 uniqueInstance = null;
    private Singleton2(){
        super();
    }
    
    public static Singleton2 getSinleton(){
        if (uniqueInstance == null) {
            uniqueInstance = new Singleton2();
        }
        return uniqueInstance;
    }
}

进阶实现方式

双重检查加锁

public class Singleton3{
    private  static volatile Singleton3 uniqueInstance = null;
    private Singleton3 (){
        super();
    }
    
    public static Singleton3 getInstance() {
        if (uniqueInstance == null){
            synchronized (Singleton3.class) {
                if (uniqueInstance == null) {
                    uniqueInstance = new Singleton3();
                }
            }
        }
        return uniqueInstance;
    }
}

静态内部类

public class Singleton4{
    
    private Singleton4() {
        super();
    }
    private static  class Holder{
        private static final Singleton4 uniqueInstance = new Singleton4();
    }
    
    public static final Singleton4 getInstance(){
        return Holder.uniqueInstance;
    }
}

二、分析与比较

饿汉式: 在类加载时就创建对象,无论是否使用都会创建,天生线程安全。

懒汉式:延迟化实例,在使用时才会创建,线程不安全,相比饿汉式来说对于资源敏感的对象很重要,能节省系统资源。

双重校验:延迟化实例,线程安全,但是牺牲性能来提升安全。

静态内部类:只有在,内部类在第一次调用Holder.uniqueInstance时才会创建实例,所以也是一种延迟化实例的机制,通过静态内部类只有第一次引用才会被加载,所以是线程安全的;并且通过反射,也无法从外部类获取内部类的属性。所以这种形式,很好的避免了反射入侵。

三、总结

为什么进行双重校验?

由于同步范围比较精确,也可能出现安全问题,即在判断为null和加锁之间另一个线程已经创建了对象,因为使用了volitile关键字保证了对象的可见性,所以必须在此进行二次检查,否则式去了同步的意义。

如何选择适当的方案?

①系统是否是资源敏感型?

如果对系统资源不敏感,懒汉式式一种不错的选择!

②是否有性能上考虑?

如果没有性能上考虑,可以使用懒汉式!

如果有性能考虑,应使用双重检查加锁或静态内部类!

注:静态内部类也有一些缺点,需要两个类才能实现,虽然不会创建静态内部类的对象,但是其 Class 对象还是会被创建,而且是属于永久代的对象。

我的个人博客(后台建站,Tomcat集群,Redis分布式,nginx,适合初学者)

猜你喜欢

转载自www.cnblogs.com/liqiangchn/p/9085384.html