枚举实现单例的原理

最近因为工作需要需要实现单例模式,考虑到单例模式最简单的实现方式是枚举实现,因此研究了下枚举实现单例模式的原理,下面将从原理、详解两个步骤说明:
一:原理
1、单例模式利用了“()” 方法在类加载的过程中线程安全的实例化了一个实例;
【 “()” 是由编译器自动收集类中的所有类变量(static)的赋值动作和静态语句块(static{})块中的语句合并产生的。因此,private static Singleton singleton = new Singleton();也会被放入到这个方法中。】
2、枚举类的构造器是private私有的,保障了内存中只有枚举的一个实例;
二:详解
1)、为什么说枚举实例是单例且线程安全的?
就拿枚举来说,其实Enum就是一个普通的类,它继承自`java.lang.Enum类。

public enum SingletonEnum{
                SINGLETON;
            }  
 对Singleton进行反编译可以得到如下java类:
public final class SingletonEnum extends Enum<SingletonEnum> {
      public static final SingletonEnum SINGLETON;
      public static SingletonEnum[] values();
      public static SingletonEnum valueOf(String s);
      static {};
}

由反编译后的代码可知,SINGLETON被声明为 static 的【 public static final SingletonEnum SINGLETON<==>public static final SingletonEnum SINGLETON = New SingletonEnum ();】,根据类加载过程可以知道虚拟机会保证一个类的() 方法在多线程环境中被正确的加锁、同步。所以,枚举实现是在实例化时是线程安全。
2)、如何保证枚举实例的单例?
首先

public enum SingletonEnum{
                SINGLETON;
            }  

的实质是:

public enum SingletonEnum{
                SINGLETON;
                ......
                private SingletonEnum(){......}
            }  

因此外部无法通过构造器创建枚举类的实例,这也是枚举类通常用来保存常量的一个原因之一。
其次,枚举类的实例会在类加载的时候线程安全的进行初始实例化,在类加载的时候,JVM会对()方法加锁,其他线程都需要阻塞等待,直到活动线程执行()方法完毕。需要注意的是,其他线程虽然会被阻塞,但如果执行()方法的那条线程退出()方法后,其他线程唤醒后不会再次进入()方法。同一个类加载器下,一个类型只会初始化一次。
综上所述,枚举保证了枚举实例的线程安全和单例性;

参考文章:
浅谈使用单元素的枚举类型实现单例模式
java回顾篇—static和非static的区别
一个简单java程序的运行全过程
static关键字的四种用法


Reprint please specify: Blog4Jun 枚举实现单例的原理

Previous
梦想是一个天真的词,实现梦想是一个残酷的词 梦想是一个天真的词,实现梦想是一个残酷的词
梦想是一个天真的词,实现梦想是一个残酷的词。今天我要探索人工智能啦!
2018-12-04 Pursue
Next
码农进化之Oracle学习篇 码农进化之Oracle学习篇
1.oracle-c/s C/S结构:client/server 客户端 服务器特点:客户端程序比较大。优点:服务器的压力比较小。很多计算都是在客户端本地计算的。运行客户端加载会比较快。客户端运行的效果比较好。有单独的客户端运行的程序
2018-12-04 Pursue