单例模式的五种实现方式

来源:互联网 发布:广东玉米数据网账号 编辑:程序博客网 时间:2024/05/27 20:20

      单例模式可以说是23中设计模式中应用最广的一种模式了。 

      定义:确保某一个类只有一个实例,自行实例化并且想整个系统提供这个实例。

      使用场景:避免某个类产生多个对象而消耗过多的资源,确保某个类在程序中只有一个实例。比如我们使用的图片加载器ImageLoader。往往单例创建的对象,耗费的资源都比较多,所以在初始化单例对象的时候就显得尤为重要了,接下来,我们就来聊一聊单例的几种实现方式。

一、饿汉式

public class ImageLoader{     private static ImageLoader instance = new ImageLoader;     private ImageLoader(){}     public static ImageLoader getInstance(){        return instance;   }}

饿汉式顾名思义,就是这个汉子很饿,一上来就把单例对象创建出来了,要用的时候直接返回即可,这种可以说是单例模式中最简单的一种实现方式。但是问题也比较明显。单例在还没有使用到的时候,初始化就已经完成了。也就是说,如果程序从头到位都没用使用这个单例的话,单例的对象还是会创建。这就造成了不必要的资源浪费。所以不推荐这种实现方式。

二、懒汉式

public class ImageLoader{     private static ImageLoader instance;     private ImageLoader(){}     public static synchronized ImageLoader getInstance(){             if(instance == null){                  instance = new ImageLoader();            }             return instance;      }}

饿汉式也顾名思义,就是这个汉子比较懒,一开始的时候什么也不做,知道要使用的时候采取创建实例的对象。看起来还不错,只有在使用实例的时候,我们才回去创建对象。但是细心的同学可能发现了,我们在获取实例的方法上加了锁,避免多线程引发的创建多个单例的情况。多线程的问题是避免了,但也造成了整体性能的下降,每次使用单例对象,都需要锁判断,降低了整体性能。很明显,懒汉式也不是我们所要追求的目标。

三、Double CheckLock实现单例

英文稍好点的东西,应该都看懂了,DCL也就是双重锁判断机制,直接上代码。

public class ImageLoader{     private static ImageLoader instance;     private ImageLoader(){}     public static ImageLoader getInstance(){           if(instance == null){                   synchronized (ImageLoader.class){                        if(instance == null){                           instance = new ImageLoader();                           }                    }             }              return instance;         }}

可以看到,在获取单例对象的时候,我们先进行了两为空判断,并且在第二次判断前加了锁,这就让程序变得更加优秀,在使用的时候,只会前几次获取单例对象的时候会进行锁判断,一旦单例对象创建完成,锁的任务也就完成了,在懒汉式的基础上,提高了性能。DCL是使用最多的单例实现方式,能够在使用的时候才进行单例对象的初始化创建,并且能够在绝大多数情况下保证对象的唯一性的正确性。请注意,是绝大多数情况下,也就是说,这种模式也不能完全保证单例的对象的完美实现,但是,就一般情况下,这种模式都能满足需求。俗话说,学无止境,接下来我们就来看看单例模式的终极实现版本。

四、静态内部类实现模式

直接上代码

public class ImageLoader{    private static class InnerInstance{       private static final ImageLoader instance = new ImageLoader();    }    private ImageLoader(){}    public static ImageLoader(){        return InnerInstance.instance;   }}


可以发现这种方式,并未加锁,因为第一次加载ImageLoader类时,并不会实例化单例对象,只有第一次调用getInstance()方法时会导致虚拟机加载InnerInstance类,这种
方式不仅能保证对象的单一性,还避免加锁带来的性能问题,又启动了延迟加载的优化,所以这就是单例模式的终极实现版本,也是推荐使用的方式。

0 0