枚举单例(Enum Singleton)是实现单例模式的一种新方式,尽管单例模式在java中已经存在很长时间了,但是枚举单例相对来说是一种比较新的概念,枚举这个特性是在Java5才出现的,这篇文章主要讲解关于为什么我们应该使用枚举来实现单例模式,它与传统方式实现的单例模式相比较又有哪些优势?

1. 枚举写法简单

写法简单这是它最大的优点,如果你先前写过单例模式,你应该知道即使有DCL(double checked locking) 也可能会创建不止一个实例,尽管在Java5这个问题修复了(jdk1.5在内存模型上做了大量的改善,提供了volatile关键字来修饰变量),但是仍然对新手来说还是比较棘手。对比通过double checked locking 实现同步,枚举单例那实在是太简单了。如果你不相信那么对比下面代码,分别为传统的用double checked locking实现的单例和枚举单例。

枚举实现:

下面这段代码就是声明枚举实例的通常做法,它可能还包含实例变量和实例方法,但是为了简单起见,我并没有使用这些东西,仅仅需要小心的是如果你正在使用实例方法,那么你需要确保线程安全(如果它影响到其他对象的状态的话)。默认枚举实例的创建是线程安全的,但是在枚举中的其他任何方法由程序员自己负责。

1
2
3
4
5
6
/**
* Singleton pattern example using Java Enumj
*/
public enum EasySingleton{
    INSTANCE;
}

你可以通过EasySingleton.INSTANCE来访问,这比调用getInstance()方法简单多了。

double checked locking 实现法:

下面代码就是用double checked locking 方法实现的单例,这里的getInstance()方法要检查两次,确保是否实例INSTANCE是否为null或者已经实例化了,这也是为什么叫double checked locking 模式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* Singleton pattern example with Double checked Locking
*/
public class DoubleCheckedLockingSingleton{
     private volatile DoubleCheckedLockingSingleton INSTANCE;
     private DoubleCheckedLockingSingleton(){}
     public DoubleCheckedLockingSingleton getInstance(){
         if(INSTANCE == null){
            synchronized(DoubleCheckedLockingSingleton.class){
                //double checking Singleton instance
                if(INSTANCE == null){
                    INSTANCE = new DoubleCheckedLockingSingleton();
                }
            }
         }
         return INSTANCE;
     }
}

你可以使用 DoubleCheckedLockingSingleton.getInstance()来获取实例。

从创建一个lazy loaded thread-safe单例来看,它的代码行数与枚举相比,后者可以全部在一行内完成,因为枚举创建的单例在JVM层面上也能保证实例是thread-safe的。

人们可能会争论有更好的方式去写单例用来替换duoble checked locking 方法,但是每种方法有他自己的优点和缺点,象我很多时候更愿初始化通过类加载静态字段,如下所示,但是记住他不是lazy loaded形式的单例。

静态工厂实现法:

这是我最喜欢的一种方式来实现单例模式,因为单例是静态的final变量,当类第一次加载到内存中的时候就初始化了,所以创建的实例固然是thread-safe。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* Singleton pattern example with static factory method
*/
public class Singleton{
    //initailzed during class loading
    private static final Singleton INSTANCE = new Singleton();
    //to prevent creating another instance of Singleton
    private Singleton(){}
    public static Singleton getSingleton(){
        return INSTANCE;
    }
}

你可以调用Singleton.getSingleton()获取实例。

2. 枚举自己处理序列化

传统单例存在的另外一个问题是一旦你实现了序列化接口,那么它们不再保持单例了,因为readObject()方法一直返回一个新的对象就像java的构造方法一样,你可以通过使用readResolve()方法来避免此事发生,看下面的例子:

1
2
3
4
//readResolve to prevent another instance of Singleton
    private Object readResolve(){
        return INSTANCE;
    }

这样甚至还可以更复杂,如果你的单例类维持了其他对象的状态的话,因此你需要使他们成为transient的对象。但是枚举单例,JVM对序列化有保证。

3. 枚举实例创建是thread-safe

正如在第一条中所说的,因为创建枚举默认就是线程安全的,你不需要担心double checked locking。

总结:枚举单例有序列化和线程安全的保证,而且只要几行代码就能实现是单例最好的的实现方式,不过你仍然可以使用其它的方式来实现单例,但是我仍然得不到一个更有信服力的原因不去使用枚举。如果你有的话,不妨告诉我。

单例模式中为什么用枚举更好相关推荐

  1. 线程的同步之Synchronized在单例模式中的应用

    synchronized在单例模式中的使用 在单例模式中有一种懒汉式的单例,就是类初始化的时候不创建对象.等第一次获取的时候再创建对象.这种单例在单线程下是没有问题的获取的也都是同一个对象.但是如果放 ...

  2. JS中的可枚举属性与不可枚举属性的学习以及扩展

    最近在学习对象遍历的方法时总是能看到的两个词,一个是"原型",一个是"枚举属性".一开始感觉自己大概明白"枚举属性"的意思,但是叫我解释却又 ...

  3. Java 枚举enum 枚举的来由 枚举的常用方法 枚举的构造函数 枚举中的方法 枚举继承接口

    Java5新增的特性,一种特殊的类型.本质上是一个类,但是有特殊的约束.这些约束让枚举更简洁.安全. 枚举本质是在一个常量集合,一个属于同一类型的常量集合.比如:四季(春夏秋冬).星期(一到七) 1. ...

  4. 选择排序_在N + 1场景中,使用@NamedEntityGraph更有选择地加载JPA实体

    选择排序 N + 1问题是使用ORM解决方案时的常见问题. 当您将某些@OneToMany关系的fetchType设置为lazy时,会发生这种情况,以便仅在访问Set / List时才加载子实体. 假 ...

  5. 将外部知识整合到群体智能中,以获得更具体的知识

    Incorporating External Knowledge into Crowd Intelligence for More Specific Knowledge Acquisition 关键知 ...

  6. TabLayout让Fragment在ViewPager中的滑动切换更优雅

    TabLayout让Fragment在ViewPager中的滑动切换更优雅 转载于:https://www.cnblogs.com/zhujiabin/p/7382500.html

  7. (转)flex中使用swc实现更好的界面代码分离

    flex中使用swc实现更好的界面代码分离 转自:http://www.cnblogs.com/yjmyzz/archive/2010/07/26/1785265.html 前几天写过一篇" ...

  8. Spring Boot 单例模式中依赖注入问题

    在日常项目开发中,单例模式可以说是最常用到的设计模式,项目也常常在单例模式中需要使用 Service 逻辑层的方法来实现某些功能.通常可能会使用 @Resource 或者 @Autowired 来自动 ...

  9. 1019. 链表中的下一个更大节点

    2020-05-15 1.题目描述 链表中的下一个更大节点 2.题解 我是将他转化为数组来求解下一个比它大的数 3.代码 /*** Definition for singly-linked list. ...

  10. java实体类中有枚举类型_当实体类中entity/DTO/VO等类中,有枚举值,应该怎么输出?...

    当实体类中entity/DTO/VO等类中,有枚举值,应该怎么输出? 问题: orderStatus 和 payStatus都是枚举类,并且枚举的个数达地10来个,我们不可能在模板页面(jsp/ftl ...

最新文章

  1. Spring ShedLock指南
  2. Shell中的read语句
  3. 数据压缩之经典——哈夫曼编码(Huffman)
  4. 中国宽带最新速率状况报告 你家达标了吗?
  5. VMware Horizon View 的内部版本号和版本 (2143853) -2020-10-27更新
  6. 从 RequireJs 源码剖析脚本加载原理
  7. html页面 关键字高亮,HTML高亮关键字的完美解决方案
  8. 微软的学术可视化搜索
  9. 阿里王坚:每一个物体都将是互联网终端
  10. shellcode加载器--从入门到放弃
  11. 用c语言写一个自动售货机
  12. 软件工程实训有必要吗_软件工程专业实训心得体会
  13. 计算机动态图显示原理,30张传感器工作原理动态图
  14. 投资银行理论与实务(一):投资银行学概论
  15. Java获取当前时间的前几分钟的时间
  16. 工作很重要,但别忘了休息
  17. QQ机器人相关指令实现-对接小夹子
  18. Nginx rewrite 和 proxy_pass共用
  19. 新媒体销售人要大胆开口
  20. DevOps平台之看板设计

热门文章

  1. 阶段3 2.Spring_01.Spring框架简介_06.spring的体系结构
  2. JFinal Template Engine 使用
  3. P3970 [TJOI2014]上升子序列
  4. cpu的用户态和内核态和内存的用户空间内核空间
  5. [Surface] 在win8.1上使用QQ截图放大问题(解决办法)
  6. 四个数学软件主要特点
  7. 利用正则表达式 替换字符串中多个 URL
  8. GARFIELD@02-21-2005
  9. 导入web项目运行报错找不到包
  10. 物流管理系统(SSM+vue+shiro)【前后台】