Head-First单例模式

205 阅读3分钟

定义

确保一个类只有一个实例,并提供一个全局访问点。

/**
 * “双重检查加锁”
 * Author: zyfu
 * Date: 2020/1/20 14:37
 */
public class Singleton {
    /*
    volatile 确保:当instance 变量被初始化时,多个线程正确的处理变量。
     Volatile可以看做是轻量级的 Synchronized,它只保证了共享变量的可见性。
    在线程 A 修改被 volatile 修饰的共享变量之后,线程 B 能够读取到正确的值。 
    java 在多线程中操作共享变量的过程中,会存在指令重排序与共享变量工作内存缓存的问题。
     */
    private volatile static Singleton instance;
    //构造方法私有化
    private Singleton(){}

    //静态方法获取实例对象
    public static Singleton getInstance(){
        //双重检查加锁
        if (instance == null) {
            synchronized (Singleton.class) {
            //第一次才会执行synchronized中的代码
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

以上是单例模式的懒汉式,当第一次调用getInstance()方法时才会创建Singleton对象。

/**
 * 饿汉式创建实例
 * Author: zyfu
 * Date: 2020/1/20 14:34
 */
public class Singleton2 {
    /**
     * 急切创建实例,jvm在加载类时创建实例,
     * 访问getInstance()方法之前,一定会先创建实例
     */
    private static Singleton2 instance = new Singleton2();

    private Singleton2(){}

    public static Singleton2 getInstance() {
        return instance;
    }
}

以上是饿汉式创建实例,当类被加载时创建实例。

单例模式特点

  • 私有化构造器
  • 提供一个全局访问点(公开的静态方法用于获取实例对象)

类加载器对单例模式的影响?

多个类加载器会各自创建自己的单例对象。每个类加载器有定义了一个命名空间,不同的类加载器可能会加载同一个类,从整个程序来看,同一个类被加载多次,从而产生多个单例实例对象。所以,当程序中有多个类加载器有同时使用了单例模式,需要注意!!解决办法:自行指定类加载器,并指定同一个类加载器。

总结

  • OO原则
  1. 封装变化
  2. 多用组合,少用继承
  3. 针对接口编程,不针对实现编程
  4. 为交互对象之间的松耦合设计而努力
  5. 类应该对扩展开放,对修改关闭
  6. 依赖抽象,不要依赖具体类
  • 要点
  1. 单例模式确保程序中一个类最多只有一个实例。
  2. 单例模式也要提供访问这个实例的全局点。
  3. 在java中实现单例模式需要私有化构造器、一个静态方法和一个静态变量
  4. 确保在性能和资源上的限制,然后小心的选择适当的方案来实现单例模式,已解决多线程的问题(一般认为所有的程序都是多线程的)。
  5. 如果使用多个类加载器,可能导致单例模式失效而产生多个实例对象。
  6. java 1.2及以前的版本必须建立单例注册表,避免GC回收单例(现在还有用这么低版本的吗????)