单例模式:确保某一个类有且只有一个实例,而且自行实例化并向整个系统提供这个实例。
类图
饿汉式单例
代码实现
package com.huey.pattern.singleton; public class HungrySingleton { /** * 在加载类之前初始化实例 */ private static HungrySingleton singleton = new HungrySingleton(); private HungrySingleton() {} public static HungrySingleton getInstance() { return singleton; } }
懒汉式单例
实现代码
package com.huey.pattern.singleton; public class LazySingleton { private static LazySingleton singleton = null; /** * 私有的构造方法,无法通过 new 操作符创建实例 */ private LazySingleton() {} /** * 获取单例,线程安全的 * @return */ public synchronized static LazySingleton getInstance() { if (singleton == null) { singleton = new LazySingleton(); } return singleton; } }
饿汉式与懒汉式的比较
懒汉式
优点:不会产生内存浪费,因为共享实例对象开始没有被初始化,而是在获得对象的方法中动态生成实例的。
缺点:在获取共享对象的方法上,使用 syschronized 线程同步,执行效率有所降低。
恶汉式
优点:由于没有 syschronized 线程同步,执行效率高。
缺点:会产生内存浪费,因为在加载 HungrySingleton 类时就已经初始化共享对象实例。
枚举型单例
懒汉式和饿汉式都利用私有构造器实现 Singleton 类,当要使得类可序列化时,仅仅在声明中加上 "implements Serializable" 是不够的。为了维护并保证 Singleton,必须声明所有实例域都是瞬时的(transient),并提供一个 readResolve 方法。否则,每次反序列化时,都会创建一个新的实例。
private Object readResolve() { return INSTANCE; }
从 Java 1.5 发行版起,实现 Singleton 还有第三种方法。只需编写一个包含单个元素的枚举类型:
package com.huey.pattern.singleton; public enum EnumSingleton { INSTANCE("enum singleton"); private String val; public String getVal() { return val; } private EnumSingleton(String val) { this.val = val; } }
这种方法更加简洁,无偿地提供了序列化机制,绝对防止多次实例化。