浅谈singleton枚举单例模式
一、前言
单例模式比较简单,可以说没有复杂的调用和接口的设计,就是一个简单的类,只是要求这个类只生成一个对象,无论什么时候都要保证这一点,因此只能生成一个实例的模式就是单例模式。
二、类的加载
类的加载是通过类加载器(Classloader)完成的,它既可以是饿汉式加载类,也可以是懒汉式加载,这跟不同的JVM实现有关。加载完类后,类的初始化就会发生,如果是对一个类的主动使用就会初始化对象,对类的被动使用不会对类进行初始化,比如final修饰的静态变量如果能在编译时就确定变量的取值,会被当做常量,作为对一个类的被动使用不会导致类的初始化。以下情况类被初始化:
类初始化的一些规则:
- 类从顶到底的顺序初始化,所以声明在顶部的字段遭遇底部的字段初始化;
- 超类早于子类和衍生类的初始化;
- 如果类的初始化是由于访问静态域而触发,那么只能声明静态域的类才被初始化,而不会触发超类的初始化或者子类的初始化,即使静态域被子类或子接口或者它的实现类锁引用;
- 接口初始化不会导致父接口的初始化;
- 静态域的初始化时在类的静态初始化期间,非静态域的初始化是在类的实例创建期间,这意味着静态域初始化在非静态域之前;
- 非静态域通过构造器初始化,子类在做任何初始化之前构造器会先调用父类的构造器,它保证了父类非静态或实例变量初始化早于子类;
三、单例模式的特点
单例模式有以下特点:
- 单例类只能有一个实例。
- 单例类必须自己创建自己的唯一实例。
- 单例类必须给所有其他对象提供这一实例。
目的:单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例。在计算机系统中,线程池、缓存、日志对象、对话框、打印机、显卡的驱动程序对象常被设计成单例。这些应用都或多或少具有资源管理器的功能。每台计算机可以有若干个打印机,但只能有一个打印服务,以避免两个打印作业同时输出到打印机中。每台计算机可以有若干通信端口,系统应当集中管理这些通信端口,以避免一个通信端口同时被两个请求同时调用。总之,选择单例模式就是为了避免不一致状态,避免政出多头。
四、饿汉式单例
public class Singleton { private Singleton() {} private static final Singleton single = new Singleton(); //静态工厂方法 public static Singleton getInstance() { return single; } }
因为这本身就是static修饰的方法,所以是在类加载的时候被创建,后期不会再改变,所以线程是安全的。
五、懒汉式单例
public class SingletonTest { public static SingletonTest singleton = null; public static SingletonTest getInstance(){ if(singleton == null){ singleton = new SingletonTest(); System.out.println("创建一次"); } return singleton; } public void show(){ System.out.println("我是江疏影"); } public static void main(String[] args) { SingletonTest singleton = SingletonTest.getInstance(); SingletonTest singleton1 = SingletonTest.getInstance(); singleton.show(); singleton1.show(); if(singleton==singleton1){ System.out.println("该对象的字符串表示形式:"); System.out.println("singleton :"+singleton.toString()); System.out.println("singleton1:"+singleton1.toString()); } } }
懒汉式方法总是会出现这样或那样的问题的,因为考虑到了多线程机制,实现起来比较麻烦,并且还会出现问题,就算是使用了一定的解救办法(同步、加锁、双重判断)的办法,性能还是被损耗了,因此懒汉式方法的弊端非常大。
六、双检锁/双重校验锁
描述:采用双锁机制,安全且在多线程情况下能保持高性能。多线程安全
package designMode; public class Singleton { private volatile static Singleton singleton; public static synchronized Singleton getSingleton(){ if(singleton==null){ singleton = new Singleton(); } return singleton; } }
或者使用如下方式,双重判断,第二次判断就是防止已经有一个对象产生了,因此也可以达到相应的目的。
package designMode; public class Singleton { private volatile static Singleton singleton; public static Singleton getSingleton(){ if(singleton==null){ synchronized (Singleton.class) { if (singleton == null) { singleton = new Singleton(); } } } return singleton; } }
这里的两次判断,第一判断:效率,第二判断:避免同步。之所以这样是因为避免加锁后,再次加锁。大大增强了执行效率。
七、枚举实现单例
1、枚举单例(Enum Singleton)在Effective Java一书中提到,因为其功能完善,使用简洁,无偿的提供了序列化机制,在面对复杂的序列化或者反射攻击时依然可以绝对防止多次实例化等优点,被作者所推崇。
2、枚举单例写法简单
如上文提到的DCL(double checked locking),实在是优点麻烦,枚举单例相对简单的多。下面这段代码就是声明枚举实例的通常做法,它可能还包含实例变量和实例方法,枚举单例是线程安全的。
public enum DataSourceEnum { DATASOURCE; private DBConnection connection = null; private DataSourceEnum(){ connection = new DBConnection(); } public DBConnection getConnection(){ return connection; } }
public class Test { public static void main(String[] args) { DBConnection conn1 = DataSourceEnum.DATASOURCE.getConnection(); DBConnection conn2 = DataSourceEnum.DATASOURCE.getConnection(); System.out.println(conn1 == conn2); } }
八、总结
在这个单例模式中,我希望大家不要只知道单例的思想,更要知道类的加载和初始化时机,以及多线程的机制,我想这才是真正有意义的呢。枚举单例有序列化和线程安全的保证,而且实现简单,是实现单例最好的方式。

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
把微软、MongoDB 与华为放到一起,为什么?
作者:开源中国(OSCHINA) 内容来源:开源中国(OSCHINA) 最近开源中国(OSCHINA)在庆祝 11 周年生日,编辑部借着这个机会梳理了一下这一年来我们追过的那些开源界/开发界的热点新闻,算作一个阶段性小结。(其实只有 9 个月~) 今年这几个月下来,已经积累了庞大规模的内容,我们按不同方向整理成了数篇文章,接下来会陆续推出,这是第二篇,聊聊在开源上最受关注的几家公司。 上一篇:编程语言这一年:Rust、Kotlin 上位,Python 横行 OSCHINA 今年关注了什么之——公司与开源 前一篇我们梳理了一下编程语言方面的动态,而编程语言之外,今年在开发者中引起最为热烈讨论的可能要数华为相关的信息了。华为与微软、MongoDB 被我们划分在“今年在开源上让人眼前一亮的公司”中,梳理成这第二篇总结文章,下边来看看。 华为 由中美贸易争端引起,华为被美国封杀,并且蔓延到技术领域。在美国政令下,谷歌开始限制华为使用安卓,微软随后停止华为订单,紧接着,SD 卡协会、Wi-Fi 联盟、IEEE 学术委员会等均撤销华为会员资格(后又接连恢复)。 绝地反击,华为宣布将推出自主研发的海...
- 下一篇
面试官问你B树和B+树,就把这篇文章丢给他
原文链接:面试官问你B树和B+树,就把这篇文章丢给他 1 B树 在介绍B+树之前, 先简单的介绍一下B树,这两种数据结构既有相似之处,也有他们的区别,最后,我们也会对比一下这两种数据结构的区别。 1.1 B树概念 B树也称B-树,它是一颗多路平衡查找树。二叉树我想大家都不陌生,其实,B树和后面讲到的B+树也是从最简单的二叉树变换而来的,并没有什么神秘的地方,下面我们来看看B树的定义。 每个节点最多有m-1个关键字(可以存有的键值对)。 根节点最少可以只有1个关键字。 非根节点至少有m/2个关键字。 每个节点中的关键字都按照从小到大的顺序排列,每个关键字的左子树中的所有关键字都小于它,而右子树中的所有关键字都大于它。 所有叶子节点都位于同一层,或者说根节点到每个叶子节点的长度都相同。 每个节点都存有索引和数据,也就是对应的key和value。 所以,根节点的关键字数量范围:1 <= k <= m-1,非根节点的关键字数量范围:m/2 <= k <= m-1。 另外,我们需要注意一个概念,描述一颗B树时需要指定它的阶数,阶数表示了一个节点最多有多少个孩子节点,一般用...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- SpringBoot2整合Thymeleaf,官方推荐html解决方案
- SpringBoot2整合Redis,开启缓存,提高访问速度
- CentOS7编译安装Gcc9.2.0,解决mysql等软件编译问题
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- CentOS7设置SWAP分区,小内存服务器的救世主
- 设置Eclipse缩进为4个空格,增强代码规范
- CentOS7安装Docker,走上虚拟化容器引擎之路
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- Hadoop3单机部署,实现最简伪集群