GoF 创建型 单例模式

单例模式的定义

保证一个类仅有一个实例,并提供一个访问他的全局访问点。

单例模式的本质

控制实例的数量

单例模式的范围

一个ClassLoader加载的是一个实例,多个ClassLoader就算装载的类是单例也会产生多个实例。

单例模式的应用

  • 全局唯一实例。
  • 缓存(空间换时间。饥汉式属于空间换时间,懒汉式属于时间换空间)。
  • 延迟加载。
  • 可以控制实例个数(使用Map、缓存的思想)。

示例1 饥汉式

public class Singleton {
    private Singleton() { }

    private static Singleton singleton = new Singleton();

    public static Singleton getInstance() {
        return singleton;
    }
}

示例2 懒汉式-双重检查锁式

双重检查锁的方式未必线程安全。
据说JDK1.4及以下有些虚拟机会因为加了volatile关键字导致双重检查锁失败,JDK1.5以上才行

/**
 * 双重检查锁的单例模式未必线程安全,需要配合volatile关键字
 */
public class Example {

    private Example(){}

    /** 使用volatile限制指令重排 */
    private volatile static Example instance = null;

    // 1、memory = allocate() 分配对象的内存空间
    // 2、ctorInstance() 初始化对象
    // 3、instance = memory 设置instance指向刚分配的内存

    // jvm和cpu优化,指令重排序

    // 1、memory = allocate() 分配对象的内存空间
    // 3、instance = memory 设置instance指向刚分配的内存
    // 2、ctorInstance() 初始化对象

    public static Example getInstance() {
        // 线程B进来发现instance有值了,返回。
        // 可能这时候因为指令重排序还没有初始化对象,所以双重检查也未必线程安全
        // 使用volatile限制指令重排
        if (null == instance) {
            synchronized (Example.class) {
                if (null == instance) {
                    //线程A 可能执行了1、3两步
                    instance = new Example();
                }
            }
        }
        return instance;
    }

}

示例3 懒汉式-内部类式

JVM隐含的同步控制:

  • 由静态初始化器(static字段或者static{}块中初始化)初始化数据时。
  • 访问final字段时。
  • 在创建线程之前创建对象时。
  • 线程可以看见它将要处理的对象时。

反序列化之后hashcode会变化。
在代码中加上Object readResolve() 方法名和返回值必须是这个,不然是不会自动调用的。

import java.io.ObjectStreamException;
import java.io.Serializable;

/** 内部类式单例模式 */
public class SerializableSingleton implements Serializable {

    private static final long serialVersionUID = -6030119137374450834L;

    /** 嵌套类,只有被使用才会装载,从而实现延迟加载。 */
    private static class InnerClass{
        /** 静态初始化器,由JVM保证线程安全 */
        private static final SerializableSingleton INSTANCE = new SerializableSingleton();
    }

    private SerializableSingleton(){}

    public static SerializableSingleton getInstance(){
        return InnerClass.INSTANCE;
    }

    protected Object readResolve() throws ObjectStreamException {
        System.out.println("调用了readResolve方法");
        return InnerClass.INSTANCE;
    }
}

你可能感兴趣的:(GoF 创建型 单例模式)