单例模式

来源:互联网 发布:2.0音箱 知乎 编辑:程序博客网 时间:2024/06/07 00:36

总结常见的单例模式

1.单例模式概述

  单个例子模式定义应该是这样的:一个类在被使用的时候只能有一个实例化对象,这种模式就称为单例模式。概念不难,实现这个模式有相应的套路,前人已经为我们总结出了经验。大致思路是这样的:为了在使用这个类时不产生多个对象,首先构造方法要私有,第二,构造一个静态方法产生这个单个实例。基于这两点思想,同时考虑多线程情况下使用这个类也只生成一个对象,总结出以下4种写法。

2.单例分类

  单例模式的实现有两种类型,饿汉式和懒汉式。

饿汉式:

/** * 单例模式(饿汉式) */class Singleton{    public static final Singleton instance = new Singleton();    private Singleton(){}    public static Singleton getInstance(){        return instance;    }}

  这是最简单的一种单例模式,称为饿汉式,在Singleton类加载时,instance对象就初始化了,而在外部只能通过调用getInstance静态方法得到这个唯一的对象,因为构造方法私有了,无法new一个对象。不管是否调用getInstance方法,在类加载过程中都创建好了实例,同时也避免了多线程下调用getInstanc方法而产生的线程安全问题,缺点是无论是否调用getInstance方法,对象都已创建,这样会占用一定的内存空间。由于这种方法比较粗暴,所以称为饿汉式。

懒汉式

  为了保证线程安全,这里介绍三种方式

第一种(常规方式)

/** * 单例模式(懒汉式) */class Singleton{    public static Singleton instance = null;    private Singleton(){}    public static synchronized Singleton getInstance(){        if (instance == null){            instance = new Singleton();        }        return instance;    }}

  这种方法在类加载时并不会初始化对象,而是在调用getInstance方法时才会初始化对象,getInstance方法使用synchronized关键字修饰可以解决线程安全问题。缺点是每次调用都会进行同步,这样对性能是有影响的。

第二种(双重校验方式)

/** * 单例模式(双重校验模式) */class Singleton{    public static Singleton instance = null;    private Singleton(){}    public static Singleton getInstance(){        if (instance == null){            synchronized (Singleton.class){                if (instance == null){                    instance = new Singleton();                }            }        }        return instance;    }}

  相较于常规方式,这种方式只在第一次实例化对象的时候需要同步,之后就不需要,这样节省性能,由于同步机制,所以要进行两次判断,所以叫双重验证方式

第三种(静态内部类方式)

/** * 单例模式(静态内部类方式) */class Singleton {    private Singleton() {}    public static class SingletonHoder {        public static final Singleton instance = new Singleton();    }    public static Singleton getInstance(){        return SingletonHoder.instance;    }}

  这是一种非常巧妙的方式,利用了静态内部类实现。这种方式利用了classloder的机制来保证初始化instance时只有一个线程,而不是只要Singleton类被装载了instance就会被实例化(没有达到lazy loading效果),Singleton类被装载了,instance不一定被初始化,因为SingletonHolder类没有被主动使用,只有显式通过调用getInstance方法时,才会显式装载SingletonHolder类,从而实例化instance。在某些情况下,如果实例化instance很消耗资源,我想让他延迟加载,我不希望在Singleton类加载时就实例化,因为我不能确保Singleton类还可能在其他的地方被主动使用从而被加载,那么这个时候实例化instance显然是不合适的。这种方式也没有使用同步,但保证了线程安全,所以相比前两种要更就显得合理一些。

3.总结

还有一种更好的方式,是《Effective Java》推荐的,就是枚举方式,这个以后再做总结。

原创粉丝点击