赞
踩
/** * 饿汉式 * 构造方法抛出异常是防止反射破坏单例 * readResolve() 是防止反序列化破坏单例 * * 创建步骤: * 1、构造器私有 * 2、私有的静态常量并初始化 * 3、提供外部访问静态方法 */ public class Singleton01 implements Serializable { private static final Singleton01 INSTANCE = new Singleton01(); private Singleton01() { // 防止反射破坏序列化 if (INSTANCE != null) { throw new RuntimeException("单例对象不能重复创建"); } System.out.println("调用了构造方法!!"); } public static Singleton01 getInstance() { return INSTANCE; } // 防止反序列化破坏单例 public Object readResolve() { return INSTANCE; } }
创建步骤:
- 构造器私有
- 私有的静态常量并初始化
- 提供外部访问静态方法
/** * 枚举饿汉式 * 好处:枚举饿汉式能天然防止反射、反序列化破坏单例 * * 创建步骤: * 1、创建常量 * 2、提供外部访问静态方法 */ public enum Singleton02 { INSTANCE; Singleton02() { System.out.println("调用了构造方法!!"); } @Override public String toString() { return getClass().getName() + "@" + Integer.toHexString(hashCode()); } public static Singleton02 getInstance() { return INSTANCE; } }
描述:好处:枚举饿汉式能天然防止反射、反序列化破坏单例。
创建步骤:
- 创建常量
- 提供外部访问静态方法
/** * 懒汉式 * 其实只有首次创建单例对象时才需要同步,但该代码实际上每次调用都会同步 * 创建步骤: * 1、构造器私有 * 2、私有的静态变量 * 3、提供外部访问静态方法(方法上加重量级锁,并且空则创建,非空直接返回) */ public class Singleton03 implements Serializable { private static Singleton03 INSTANCE = null; private Singleton03() { System.out.println("调用了构造方法!!"); } public static synchronized Singleton03 getInstance() { if (INSTANCE == null) { INSTANCE = new Singleton03(); } return INSTANCE; } }
描述:每次调用
getInstance()
方法都会加锁。比较不推荐。
创建步骤:
- 构造器私有
- 私有的静态常量并初始化
- 提供外部访问静态方法(方法上加重量级锁,并且空则创建,非空直接返回)
/** * 双检锁懒汉式 * 为什么必须加 volatile? * INSTANCE = new Singleton4() 不是原子的,分成 3 步:创建对象、调用构造、给静态变量赋 * 值,其中后两步可能被指令重排序优化,变成先赋值、再调用构造 * 如果线程1 先执行了赋值,线程2 执行到第一个 INSTANCE == null 时发现 INSTANCE 已经不为 * null,此时就会返回一个未完全构造的对象 * 创建步骤: * 1、构造器私有 * 2、私有的静态变量(volatile防止指令重排序) * 3、提供外部访问静态方法(Class对象上锁,并且提供双重检测) */ public class Singleton04 implements Serializable { private static volatile Singleton04 INSTANCE = null; // 可见性,有序性 private Singleton04() { System.out.println("调用了构造方法!!"); } public static Singleton04 getInstance() { if (INSTANCE == null) { synchronized (Singleton04.class) { if (INSTANCE == null) { INSTANCE = new Singleton04(); } } } return INSTANCE; } }
描述:设计较为繁琐。双重检测的原因是因为锁的是该类的
Class对象
,不做双重检测还是会有线程安全的问题。
创建步骤:
- 构造器私有
- 私有的静态变量(
volatile
防止指令重排序)- 提供外部访问静态方法(
Class
对象上锁,并且提供双重检测)
/** * 内部类懒汉式 * 避免了双检锁的缺点 * * 创建步骤: * 1、构造器私有 * 2、私有的静态内部类静态成员变量创建单例对象 * 3、提供外部访问静态方法 */ public class Singleton05 implements Serializable { private Singleton05() { System.out.println("调用了构造方法!!"); } private static class Holder { static Singleton05 INSTANCE = new Singleton05(); } public static Singleton05 getInstance() { return Holder.INSTANCE; } }
描述:避免了双检锁的缺点。
创建步骤:
- 构造器私有
- 私有的静态内部类静态成员变量创建单例对象
- 提供外部访问静态方法
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。