设计模式系列—单例设计模式( 三 )


静态内部类代码示例package com.niuh.designpattern.singleton.v7;/** * 静态内部类完成 , 推荐使用 */public class Singleton {// 添加 volatile 关键字 , 防止指令重排private static volatile Singleton instance;// 构造函数私有化private Singleton() {}// 写一个静态内部类 , 该类中有一个静态属性 Singletonprivate static class SingletonInstance {privatestatic final Singleton INSTANCE = new Singleton();}// 提供一个静态的公有方法 , 直接返回 SingletonInstance.INSTANCEpublic static synchronized Singleton getInstance() {return SingletonInstance.INSTANCE;}}优缺点

  • 本质上是利用类的加载机制来保证线程安全
  • 只有在实际使用的时候 , 才会触发类的初始化 , 所以也是懒加载的一种形式 。
  • 优点:避免了线程不安全 , 利用静态内部类特点实现延迟加载 , 效率高
静态内部类的方式在 singleton 类被装载时并不会被立即实例化 , 而是在需要的实例化的时候 , 调用 getInstance 方法 , 才会装载 SingletonInstance 类 , 从而完成 Singleton 的实例化 类的静态属性只会在第一次加载类的时候初始化 , 所以在这里 , JVM 帮助我们保证了线程的安全性 , 在类进行初始化的时 , 别的线程是无法进入的 。推荐上实际开发中使用
枚举代码示例package com.niuh.designpattern.singleton.v8;/** * 使用枚举 , 可以实现单例, 推荐 */public enum Singleton {INSTANCE; // 属性public void hello() {System.out.println("hello word~");}} class SingletonTest08 {public static void main(String[] args) {Singleton instance1 = Singleton.INSTANCE;Singleton instance2 = Singleton.INSTANCE;System.out.println(instance1 == instance2);System.out.println(instance1.hashCode());System.out.println(instance2.hashCode());instance1.hello();}}优缺点
  • 天然不支持反射创建对应的实例 , 且有自己的反序列化机制
  • 利用类加载机制保证线程安全
这借助 JDK1.5 中添加的枚举来实现单例模式 。 不仅能避免多线程同步问题 , 而且还能防止反序列化重新创建新的对象 , 推荐使用 。
反射攻击实例我们拿饿汉模式作为例子进行测试 , 饿汉模式的代码如下:
package com.niuh.designpattern.singleton.reflect;/** * 饿汉模式防止反射攻击 */public class HungrySingleton {private static final HungrySingleton instance;private HungrySingleton(){}static {instance = new HungrySingleton();}public static HungrySingleton getInstance(){return instance;}private Object readResolve(){return instance;}}先写一个利用反射获取实例的方法和直接获取实例的方法 , 将两者的返回值进行比较 , 看返回的是否是一个实例 。 代码如下:
package com.niuh.designpattern.singleton.reflect;import java.lang.reflect.Constructor;import java.lang.reflect.InvocationTargetException;/** * 反射攻击实例 */public class Reflectattack {public static void main(String[] args) throws IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchMethodException {Constructor declaredConstructor = HungrySingleton.class.getDeclaredConstructor();declaredConstructor.setAccessible(true);HungrySingleton hungrySingleton = declaredConstructor.newInstance();HungrySingleton instance = HungrySingleton.getInstance();System.out.println(hungrySingleton);System.out.println(instance);System.out.println(hungrySingleton == instance);}}


推荐阅读