设计模式系列:单例模式(Singleton)应用实践

 

 

单例模式多线程

单例模式的类,在整个内存中只有一份存在(有且只能一个new,避免功能性冲突)

 

应用场景

保证一个类仅有一个实例,并提供一个访问它的全局访问点

 

主要特点

实现单例模式三个主要特点

1、构造方法私有化(不能通过new创建很多实例);--构造函数private

2、实例化的变量引用私有化(避免线程安全);--private Object instanct ;

3、获取实例的方法共有(出口)。  --public Object getInstance();

 

 

实现方法

 

注册登记式

每使用一次,都往一个固定的容器中去注册并且将使用过的对象进行缓存,下次去取对象的时候,就直接从缓存中取值,以保证每次获取的对象都是同一个对象,IOC的单例模式,就是典型的注册登记是单例

 

设计模式系列:单例模式(Singleton)应用实践

单例和枚举

单元素的枚举类型已经成为实现Singleton的最佳方法。用枚举来实现单例非常简单,只需要编写一个包含单个元素的枚举类型即可。

 

 设计模式系列:单例模式(Singleton)应用实践

使用枚举来实现单实例控制会更加简洁,而且无偿地提供了序列化机制,并由JVM从根本上提供保障,绝对防止多次实例化,是更简洁、高效、安全的实现单例的方式。

 

序列化、反序列化(重写readResolve)

 

设计模式系列:单例模式(Singleton)应用实践

设计模式系列:单例模式(Singleton)应用实践

//自动调用这个 readResolve方法来返回我们指定好的对象了,

protected Object readResolve()

{return MyObjectInner.myObject ;}

方法readResolve允许class在反序列化返回对象前替换、解析在流中读出来的对象。实现readResolve方法,一个class可以直接控制反序化返回的类型和对象引用。 

方法readResolve会在ObjectInputStream已经读取一个对象并在准备返回前调用。ObjectInputStream 会检查对象的class是否定义了readResolve方法。如果定义了,将由readResolve方法指定返回的对象。返回对象的类型一定要是兼容的,否则会抛出ClassCastException 。

 

内部类静态变量

 

类级内部类指的是,有static修饰的成员式内部类。如果没有static修饰的成员式内部类被称为对象级内部类。

类级内部类相当于其外部类的static成分,它的对象与外部类对象间不存在依赖关系,因此可直接创建。而对象级内部类的实例,是绑定在外部对象实例中的。

类级内部类中,可以定义静态的方法。在静态方法中只能够引用外部类中的静态成员方法或者成员变量。

类级内部类相当于其外部类的成员,只有在第一次被使用的时候才被会装载。

 

设计模式系列:单例模式(Singleton)应用实践

 当getInstance方法第一次被调用的时候,它第一次读取SingletonHolder.instance,导致SingletonHolder类得到初始化;而这个类在装载并被初始化的时候,会初始化它的静态域,从而创建Singleton的实例,由于是静态的域,因此只会在虚拟机装载类的时候初始化一次,并由虚拟机来保证它的线程安全性。

这个模式的优势在于,getInstance方法并没有被同步,并且只是执行一个域的访问,因此延迟初始化并没有增加任何访问成本。

 

 

饿汉模式(static new 实例变量)

将类的静态实例作为类的一个成员变量,在JVM加载它的时候,就已经创建了该类的实例,因此不存在多线程的安全问题

写法1 静态变量

设计模式系列:单例模式(Singleton)应用实践

写法2: 静态代码块

 

设计模式系列:单例模式(Singleton)应用实践

缺点:浪费了内存(典型的空间换时间)

优点:没有加任何的锁、执行效率比较高。

 

 

懒汉模式(需要的时候再new,双重检查)

 

设计模式系列:单例模式(Singleton)应用实践

由于volatile关键字可能会屏蔽掉虚拟机中一些必要的代码优化,所以运行效率并不是很高。因此一般建议,没有特别的需要,不要使用。也就是说,虽然可以使用“双重检查加锁”机制来实现线程安全的单例,但并不建议大量采用,可以根据情况来选用。

 

扩展

思考:设计模式系列:双重检查加锁安全吗?