单例模式
单例模式
定义:某个类仅有一个唯一的实例,并且提供一个全局的访问点来访问这一实例。
注意:
1.该类只能有一个实例
2.必须是自己创建的这一个唯一的实例
3.必须自己向整个系统提供这个实例
代码实现:
1.目的是一个类只有一个实例,并且提供全局的访问点
2.包含的角色只有一个
3.构造函数是私有的,无法通过new对象的方式创建实例
4.有一个静态的私有成员变量和静态的共有的工厂方法
注意:
1.单例类构造器的可见行为private
2.提供一个类型为自身的静态私有成员变量
3.提供共有的静态工厂方法
优点:
1.严格控制客户程序访问其唯一的实例。
2.单例类可以自带一些子类,它的每个子类都是单例类。
3.该模式的类可以比较容易允许创建一定数目的对象类。
缺点:
1.单例模式,没有抽象层,扩展比较困难
2.在一定程度上违背了单一职责原则
3.容易导致单例状态丢失,系统存在垃圾回收机制,长时间不使用,会被系统自动回收,再次使用就需要再次实例
、
实现:
1.创建一个Singleton类
public class Singleton { //私有构造器 private Singleton(){} //私有的Singleton对象 private static Singleton instance = new Singleton(); public static Singleton getInstance(){ return instance; } public void Say(){ System.out.println("Hello Singleton"); } }
2.创建TestSingleton类:
在类里使用new 的方法是会报错的
public class TestSingleton { public static void main(String[] args) { Singleton singleton = Singleton.getInstance(); singleton.Say(); } }
3.运行结果是
Hello Singleton
单例模式的其他实现方式:
1.懒汉式,线程不安全
是否 Lazy 初始化:是
是否多线程安全:否
实现难度:易
描述:这种方式是最基本的实现方式,这种实现最大的问题就是不支持多线程。因为没有加锁 synchronized,所以严格意义上它并不算单例模式。
这种方式 lazy loading 很明显,不要求线程安全,在多线程不能正常工作。
public class Singleton { private static Singleton instance; private Singleton(){}; public static Singleton getInstance(){ if (instance == null){ instance = new Singleton(); } return instance; } }
2.懒汉式,线程安全
是否 Lazy 初始化:是
是否多线程安全:是
实现难度:易
描述:这种方式具备很好的 lazy loading,能够在多线程中很好的工作,但是,效率很低,99% 情况下不需要同步。
优点:第一次调用才初始化,避免内存浪费。
缺点:必须加锁 synchronized 才能保证单例,但加锁会影响效率。
getInstance() 的性能对应用程序不是很关键(该方法使用不太频繁)。
public class Singleton { //懒汉式 private static Singleton instance; private Singleton(){}; public static synchronized Singleton getInstance(){ if (instance == null){ instance = new Singleton(); } return instance; } }
3.饿汉式
是否 Lazy 初始化:否
是否多线程安全:是
实现难度:易
描述:这种方式比较常用,但容易产生垃圾对象。
优点:没有加锁,执行效率会提高。
缺点:类加载时就初始化,浪费内存。
它基于 classloader 机制避免了多线程的同步问题,不过,instance 在类装载时就实例化,虽然导致类装载的原因有很多种,在单例模式中大多数都是调用 getInstance 方法, 但是也不能确定有其他的方式(或者其他的静态方法)导致类装载,这时候初始化 instance 显然没有达到 lazy loading 的效果。
public class Singleton { private Singleton(){} private static Singleton instance = new Singleton(); public static Singleton getInstance(){ return instance; } }
4.双检锁/双重校验锁
JDK 版本:JDK1.5 起
是否 Lazy 初始化:是
是否多线程安全:是
实现难度:较复杂
描述:这种方式采用双锁机制,安全且在多线程情况下能保持高性能。
getInstance() 的性能对应用程序很关键。
public class Singleton { private volatile static Singleton instance; private Singleton(){} public static Singleton getInstance(){ if (instance == null){ synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; } }
5.登记式/静态内部类
是否 Lazy 初始化:是
是否多线程安全:是
实现难度:一般
描述:这种方式能达到双检锁方式一样的功效,但实现更简单。对静态域使用延迟初始化,应使用这种方式而不是双检锁方式。这种方式只适用于静态域的情况,双检锁方式可在实例域需要延迟初始化时使用。
public class Singleton { private static class Singletontest{ private static final Singleton INSTANCE = new Singleton(); } private Singleton(){}; public static final Singleton getInstance(){ return Singletontest.INSTANCE; } }
备注:
代码部分的实现以及部分讲解来源于:http://www.runoob.com/design-pattern/singleton-pattern.html