单例模式

 私有构造函数、私有静态变量以及 公有静态函数

几种形式:

1 懒汉式(不安全)

不使用时不加载

public class Singleton {
    private static Singleton instance;

    private Singleton() {
    }

    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }

}

2 饿汉 安全

public class Singleton {
    private static Singleton instance = new Singleton();
    private Singleton() {
    }
    public static Singleton getInstance() {
        return instance;
    }
}

 3 懒汉式 线程安全

加锁方式 不推荐使用

public class Singleton {
    private static Singleton instance;
    private Singleton() {
    }
    public static synchronized Singleton getInstance() {
        if(instance == null){
            instance = new Singleton();
        }
        return instance;
    }
}

4 双重检查锁 线程安全

只对实例化的部分代码进行加锁

考虑下面的实现,也就是只使用了一个 if 语句。在 uniqueInstance == null 的情况下,如果两个线程都执行了 if 语句,那么两个线程都会进入 if 语句块内。虽然在 if 语句块内有加锁操作,但是两个线程都会执行 uniqueInstance = new Singleton(); 这条语句,只是先后的问题,那么就会进行两次实例化。因此必须使用双重校验锁,也就是需要使用两个 if 语句。

uniqueInstance 采用 volatile 关键字修饰也是很有必要的, uniqueInstance = new Singleton(); 这段代码其实是分为三步执行:

  1. 为 uniqueInstance 分配内存空间
  2. 初始化 uniqueInstance
  3. 将 uniqueInstance 指向分配的内存地址

但是由于 JVM 具有指令重排的特性,执行顺序有可能变成 1>3>2。指令重排在单线程环境下不会出现问题,但是在多线程环境下会导致一个线程获得还没有初始化的实例。例如,线程 T1 执行了 1 和 3,此时 T2 调用 getUniqueInstance() 后发现 uniqueInstance 不为空,因此返回 uniqueInstance,但此时 uniqueInstance 还未被初始化。

使用 volatile 关键字为了防止指令重排

 5 静态内部类实现

当 Singleton 类加载时,静态内部类 SingletonHolder 没有被加载进内存。只有当调用 getUniqueInstance()方法从而触发 SingletonHolder.INSTANCE 时 SingletonHolder 才会被加载,此时初始化 INSTANCE 实例,并且 JVM 能确保 INSTANCE 只被实例化一次。

这种方式不仅具有延迟初始化的好处,而且由 JVM 提供了对线程安全的支持。

public class Singleton {
    private Singleton() {
    }
    public static class SingletonHolder{
        private static final Singleton Instance = new Singleton();
    }
    public static Singleton getInstance() {
       return SingletonHolder.Instance;
    }
}

6 枚举方法实现

两个 hashcode 是相同的

public enum Singleton {
    INSTANCE;
    private String objName;

    public void setObjName(String name) {
        this.objName = name;
    }

    public static void main(String[] args) {
        Singleton s1 = Singleton.INSTANCE;
        s1.setObjName("first instance");
        System.out.println(s1.objName);
        System.out.println(s1.hashCode());
        Singleton s2 = Singleton.INSTANCE;
        s2.setObjName("second instance");
        System.out.println(s2.objName);
        System.out.println(s2.hashCode());
        try

        {
            Singleton[] enumConstants = Singleton.class.getEnumConstants();
            for (Singleton enumConstant : enumConstants) {
                System.out.println(enumConstant.objName);
            }
        } catch (Exception e)
        {
            e.printStackTrace();
        }
    }
}
原文地址:https://www.cnblogs.com/zhy-study/p/10651278.html