各种单例模式的对比分析

先看一个最简单的单例模式

public class SingleA {

    //创建实例对象
    private static SingleA singleA = new SingleA();  
    
    //构造函数私有化
    private SingleA(){
        
    }
    
    //获得实例对象
    public static SingleA getInstance(){
        return singleOne;
    }
    
}

它的内部进行了三个操作:1.构造函数私有化  2.内部创建一个类的实例对象  3.提供一个获得该类实例对象的方法。

该单例模式又称为饿汉式,因为该类的实例对象是在程序运行刚开始就被创建出来了,即使程序中的其他地方还未使用到该对象。该种单例模式的缺点也正在此处,我们应该考虑如何让类的实例在引用到的时候再创建出来,于是就有了另一种单例模式。如下:

public class SingleB {
    private static SingleB singleB= null;
    
    private SingleB(){
        
    }
    
    public SingleB getInstance(){
        if(singleB == null){  //如果实例对象不存在,则创建
            singleB = new SingleB();
        }
        return singleB;
    }
    
}

这种方法相较之前的优点是只会在使用到该类的实例对象时才创建它。但是该种单例模式还有一个问题,它是线程不安全的,当两个线程同时访问该类的getInatance()方法,发现对象为空之后,都会创建实例对象,也就是说共创建了两次对象。

当然也有对应的解决方法,一般我们是在getInstance()方法前或者方法内添加Synchronized关键字来保证每次只会有一个线程访问,来保证线程的安全性。但是这种方法也有安全隐患,当两个线程并发访问时有可能会造成某个线程调用该方法返回的是一个不完整对象的引用。此时可能会产生错误!

这时我们就可以考虑使用静态内部类来实现单例模式:静态内部类有一个特点就是 只有在有引用了以后才会被装载到内存中。所以我们可以这样实现:

public class SingleC {
    
    private SingleC(){
        
    }
    
    public SingleC getInstance(){
        return SingleHolder.singleC;
    }

    private static class SingleHolder{
        private static SingleC singleC= new SingleC();
    }
}

该种方法是更加完美的懒汉式单例模式。如果你既想要实时加载单例,又想要解决并发问题,就可以考虑这种实现方法。

原文地址:https://www.cnblogs.com/weimore/p/7413221.html