标签:volatile 操作 环境 就会 hash rac 加锁 uniq out
私有构造函数、私有静态变量以及 公有静态函数
几种形式:
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();
这段代码其实是分为三步执行:
但是由于 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(); } } }
标签:volatile 操作 环境 就会 hash rac 加锁 uniq out
原文地址:https://www.cnblogs.com/zhy-study/p/10651278.html