单例模式
单例模式
这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一对象的方式,可以直接访问,不需要实例化该类的对象。
- 1、单例类只能有一个实例。
- 2、单例类必须自己创建自己的唯一实例。
- 3、单例类必须给所有其他对象提供这一实例。
1、饿汉式
是否 Lazy 初始化:否
是否多线程安全:是
实现难度:易
描述:这种方式比较常用,但容易产生垃圾对象。
优点:没有加锁,执行效率会提高。
缺点:类加载时就初始化,浪费内存。
它基于 classloader 机制避免了多线程的同步问题,不过,instance 在类装载时就实例化,虽然导致类装载的原因有很多种,在单例模式中大多数都是调用 getInstance 方法, 但是也不能确定有其他的方式(或者其他的静态方法)导致类装载,这时候初始化 instance 显然没有达到 lazy loading 的效果。
public class Singleton { private Singleton(){} private static Singleton instance = new Singleton(); public static Singleton getInstance(){ return instance; } }
2、双检锁/双重校验锁(DCL,即 double-checked locking)
JDK 版本:JDK1.5 起
是否 Lazy 初始化:是
是否多线程安全:是
实现难度:较复杂
描述:这种方式采用双锁机制,安全且在多线程情况下能保持高性能。
getInstance() 的性能对应用程序很关键。
public class Singleton2 { private Singleton2() { } private volatile Singleton2 singleton2; public Singleton2 getInstance() { if (singleton2 == null) { synchronized (Singleton2.class) { if (singleton2 == null) { singleton2 = new Singleton2(); } } } return singleton2; } }
3、饿汉模式和懒汉模式的区别
懒汉式与饿汉式的根本区别在与是否在类内方法外创建自己的对象。
并且声明对象都需要私有化,构造方法都要私有化,这样外部才不能通过 new 对象的方式来访问。
饿汉式的话是声明并创建对象(因为他饿),懒汉式的话只是声明对象,在调用该类的 getinstance() 方法时才会进行 new 对象。
4、如何选择模式
不需延迟加载,使用枚举或者饿汉式,枚举性好于饿汉式。
需要延迟加载,使用静态内部类或者懒汉式,静态内部类好于懒汉式。