代码简洁 这是迄今为止最大的优点,如果你曾经在Java5之前写过单例模式代码,那么你会知道即使是使用双检锁你有时候也会返回不止一个实例对象。
虽然这种问题通过改善java内存模型和使用volatile变量可以解决,但是这种方法对于很多初学者来说写起来还是很棘手。
相比用 synchronization的双检锁实现方式来说,枚举单例就简单多了。
你不相信?比较一下下面的双检锁实现代码和枚举实现代码就知道了。 注:文末有福利!

用枚举实现的单例:

这是我们通常写枚举单例的方式,它可能包含实例变量和实例方法,但是简单来说我什么都没用,需要注意的是如果你使用实例方法,你就需要确保方法的线程安全性,避免它会影响对象的状态。通常情况下枚举里面创建实例是线程安全的,但是其它的方法就需要编程者自己去考虑了。

public enum EasySingleton{
INSTANCE;
}

代码就这么简单,你可以使用EasySingleton.INSTANCE调用它,比起你在单例中调用getInstance()方法容易多了。

用双检索实现单例:

下面的代码是用双检索实现单例模式的例子,在这里getInstance()方法检查了两次来判断INSTANCE是否为null,这就是为什么叫双检索的原因,记住双检索在java5之前是有问题的,但是java5在内存模型中有了volatile变量之后就没问题了。

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()来获得实例对象。

现在看看二者创建一个懒加载线程安全的单例需要的代码数量。
使用枚举单例模式你只需要一行代码搞定因为枚举实例的创建是线程安全的。

你可能会说比起使用双检索方法还有更好的方法实现单例模式,但是任何一种方法都有它的利和弊,就像我下面例子中展示的我很喜欢的一种在类加载期间初始化静态域的单例实现方式,但是要记住这不是一种懒加载单例方式。

用静态工厂方法实现单例:

这是java中我比较喜欢的一种实现单例模式的方法,由于单例实例是static和final的,当类第一次被加载到内存它就实例化了,所以这种实例的创建方式是线程安全的。

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.getInstance()方法来获得实例对象。

2)枚举单例可以自己处理序列化

传统的单例模式的另外一个问题是一旦你实现了serializable接口,他们就不再是单例的了,因为readObject()方法总是返回一个 新的实例对象,就像java中的构造器一样。你可以使用readResolve()方法来避免这种情况,通过像下面的例子中这样用单例来替换新创建的实 例:

private Object readResolve(){
return INSTANCE;
}

如果你的单例类包含状态的话就变的更复杂了,你需要把他们置为transient状态,但是用枚举单例的话,序列化就不要考虑了。

3)枚举单例是线程安全的

就像第一点提到的,由于枚举实例的创建默认就是线程安全的,你不需要担心双检锁问题。

总结:通过提供序列化和线程安全并且几行代码搞定,说明枚举单例模式是java5之后创建单例最好的方法。你仍然可以使用其它你感觉很流行的方式来创建单例,但是我还是要找一个能够使我信服的观点让我不去使用枚举作为单例,如果你有,请告诉我!


推荐一个良心公众号【IT资源社】:

本公众号致力于免费分享全网最优秀的视频资源,学习资料,面试经验等,前端,PHP,JAVA,算法,Python,大数据等等,你想要的这都有

IT资源社-QQ交流群:625494093

也可添加微信拉你进微信群: super1319164238

微信搜索公众号:ITziyuanshe 或者扫描下方二维码直接关注,


作者:芥末无疆sss
链接:https://www.jianshu.com/p/7b3de9e0c983

为什么java中用枚举实现单例模式会更好的更多相关文章

  1. Java 利用枚举实现单例模式

    引言 单例模式比较常见的实现方法有懒汉模式,DCL模式公有静态成员等,从Java 1.5版本起,单元素枚举实现单例模式成为最佳的方法. Java枚举 基本用法 枚举的用法比较多,本文主要旨在介绍利用枚 ...

  2. Java枚举enum以及应用:枚举实现单例模式

    枚举作为一个常规的语言概念,一直到Java5才诞生不得不说有点奇怪,以至于到现在为止很多程序员仍然更喜欢用static final的形式去命名常量而不使用,一般情况下,Java程序员用这种方式去实现枚 ...

  3. 161208、Java enum 枚举还可以这么用

    在大部分编程语言中,枚举类型都会是一种常用而又必不可少的数据类型,Java中当然也不会例外.然而,Java中的Enum枚举类型却有着许多你意想不到的用法,下面让我们一起来看看. 先来看一段代码示例: ...

  4. Java设计模式学习记录-单例模式

    前言 已经介绍和学习了两个创建型模式了,今天来学习一下另一个非常常见的创建型模式,单例模式. 单例模式也被称为单件模式(或单体模式),主要作用是控制某个类型的实例数量是一个,而且只有一个. 单例模式 ...

  5. Java常见设计模式之单例模式

         1.何为单例模式? 单例模式是一种常用的软件设计模式.在它的核心结构中只包含一个被称为单例类的特殊类.通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的 ...

  6. Java与设计模式之单例模式(下) 安全的单例模式

          关于单例设计模式,<Java与设计模式之单例模式(上)六种实现方式>介绍了6种不同的单例模式,线程安全,本文介绍该如何保证单例模式最核心的作用——“实现该模式的类有且只有一个实 ...

  7. Java与设计模式之单例模式(上)六种实现方式

           阎宏博士在<JAVA与模式>中是这样描述单例模式的:作为对象的创建模式,单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例.这个类称为单例类.      ...

  8. Java enum枚举在实际项目中的常用方法

    在项目实际开发过程中,经常会遇到对某些固定的值.字典项的定义的需求,很多项目经常使用常量来定义,其实在jdk1.5就已经引入了枚举,使用枚举可以更好的解决这类需求,本文主要记录枚举的优势以及经常在项目 ...

  9. 《java常用设计模式之----单例模式》

    一.简介 单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一.这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式. 这种模式涉及到一个单一的类,该类负责创 ...

随机推荐

  1. 分享调用Java private方法

    上周在修复bug时,发现Java类中某方法是private,且类中没有用到,第一感觉是方法多余.其实通过分析,发现原来Native Code会通过JNI调到此方法.这也给自己启发,平时做Code re ...

  2. signalR的集群与负载均衡

    signalR是相当不错的websocket应用,最近要做集群和负载均衡 主要用到了redis进行集群,signalR的backplane集成redis. 细节,订阅redis之后注意database ...

  3. spark source code 分析之ApplicationMaster overview(yarn deploy client mode)

    一直不是很清楚ApplicationMaster的作用,尤其是在yarn client mode和cluster mode的区别 网上有一些非常好的资料,请移步: https://blog.cloud ...

  4. Centos虚拟机克隆模板

    Centos6模板 IPTABLES/SELINUX # iptalbes -F # service iptables save 或 # /etc/init.d/iptables stop # chk ...

  5. Mycat 读写分离详解

    Mycat 的读写分离是依赖数据库级别的数据主从同步的基础上来实现的(Mysql 的主从配置链接),Mycat 的读写分离是在 schema.xml 配置的 dataHost 节点的 balance ...

  6. 笔记:Maven 插件配置 - maven-jar-plugin

    在项目中内部重用某个模块的测试代码很常见的需求,可能某个底层模块的测试代码中包含一些常用的测试工具类,或者一些高质量的测试基类供继承,这个时候Maven用户就需要通过配置此插件将测试类打包,插件配置代 ...

  7. .NET Core快速入门教程 5、使用VS Code进行C#代码调试的技巧

    一.前言 为什么要调试代码?通过调试可以让我们了解代码运行过程中的代码执行信息,比如变量的值等等.通常调试代码是为了方便我们发现代码中的bug.ken.io觉得熟练代码调试技巧是成为合格程序员的基本要 ...

  8. 《PHP 设计模式》翻译完毕

    翻译进度请见:https://laravel-china.org/docs/php-design-patterns/2018?mode=sections 设计模式不仅代表着更快开发健壮软件的有用方法, ...

  9. 多线程使用Lock实现生产者实现者代码

    package cn.com.servyou.qysdsjx.thread; import java.util.ArrayList; import java.util.List; import jav ...

  10. 腾讯云python网站开发环境搭建

    前段时间腾讯云做活动,于是就花了几百大洋买了三年的云服务,准备在上 面安装python web的开发环境,下面将安装过程做一个总结,希望能够帮助大家. 一.使用环境   使用的软件环境为:CentOS ...