单例模式(Singleton)小记
概念
引用维基百科对单例的说明:
单例模式,也叫单子模式,是一种常用的软件设计模式。在应用这个模式时,单例对象的类必须保证只有一个实例存在。
继续引用维基百科的实现思路:
实现单例模式的思路是:一个类能返回对象一个引用(永远是同一个)和一个获得该实例的方法(必须是静态方法,通常使用getInstance这个名称);当我们调用这个方法时,如果类持有的引用不为空就返回这个引用,如果类保持的引用为空就创建该类的实例并将实例的引用赋予该类保持的引用;同时我们还将该类的构造函数定义为私有方法,这样其他处的代码就无法通过调用该类的构造函数来实例化该类的对象,只有通过该类提供的静态方法来得到该类的唯一实例。
单例的思路就这么简单,不像其他的设计模式那样一般有几个类。它只有一个类。
Java 中的单例实现
懒汉式与饿汉式
在讨论 Java 的单例模式时,猿们一般会提到两者实现方式:懒汉式 和 饿汉式 。为什么会有这两种叫法?看了实现代码后,相信您会忽然大悟。
饿汉式,我是饿汉,不能等,创建(类)时就要给我吃的(实例化对象),不然我会饿死:
public class Singleton{
//创建类时就实例化出单例。
private final static Singleton INSTANCE = new Singleton();
//使用私有的构造器来阻止外部(其他代码)实例化该对象
private Singleton(){}
//由于该类的构造方法是私有的,只能在该类内部实例化对象。因此必须提供一个静态的公有方法作为出口,提供单例。
public static Singleton getInstance(){
return INSTANCE;
}
}
懒汉式, 我是懒汉,你叫我干活(给 INSTANCE new 一个单例)才干,懒是我的天性,这不能怪我:
public class Singleton{
private static Singleton INSTANCE;
private Singleton(){}
public static Singleton getInstance(){
if(INSTANCE == null){
INSTANCE = new Singleton();
}
return INSTANCE;
}
}
OK,单例模式就是这么简单,结束了。呵呵,真的结束了吗?图样图森破!
上面的两个实现确实是实现了汉式和懒汉式。而且它们在单线程下能很好地运行。但如果我们把它们应用在多线程下呢?试一下就知道,饿汉式依然坚挺,潇洒应对。但懒汉式就瞬间爆炸了!没办法谁叫你懒,出来混总是要还的。即使是代码,懒也要付出代价~~开玩笑的_,爆炸的原因肯定不是懒的原因啦,是线程同步的问题,造成了非线程安全的懒汉式。
既然上面的懒汉式在多线程下爆炸了,我们就要去拯救它,总不能见死不救吧~~
多线程下懒汉式的自我拯救
知道懒汉式爆炸的原因时线程同步的问题,我们最简单的拯救方法就是直接进行同步加锁,创建线程安全的懒汉式:
public class Singleton{
private static Singleton INSTANCE;
private Singleton(){}
public static synchronized Singleton getInstance(){
if(INSTANCE == null){
INSTANCE = new Singleton();
}
return INSTANCE;
}
}
通过简单的对 getInstance 方法进行加锁就可以把非线程安全的懒汉式改为线程安全的,简单吧!但,正如天下没免费的午餐一样,如此简单的拯救方法肯定是要付出代价的。因此这种实现方法会降低效率。
好吧,效率低下,我改还不行。经过改改改后,我们又得出了另外一种线程安全懒汉式单例:双重校验锁(Double-Checked Locking)
public class Singleton{
private static volatile Singleton INSTANCE;
private Singleton(){}
public static Singleton getInstance(){
if(INSTANCE == null){
synchronized(Singleton.class){
if(INSTANCE == null){
INSTANCE = new Singleton();
}
}
}
return INSTANCE;
}
}
该方法比之前的线程安全懒汉式效率高的原因是,之前的实现方法每次获取单例是都要进行同步,每一次只能有一个线程进入 getInstance 方法获取实例;而该方法把同步块缩小了,而且只在 INSTANCE 为 null 时才会进行同步访问(也就是说只需要一次同步)。之后都不需要同步,可以并发地获取实例。
很多人都知道,JDK 1.5 之前利用这种方法实现是有问题的。但在 JDK 1.5 后,Java 的内存已经修改了,该方法在 1.5 后能正常运行,可以放心使用。
其他的实现方法
使用静态内部类实现
public class Singleton{
private static class SingletonHolder{
private static final Singleton INSTANCE = new Singleton();
}
private Singleton(){}
public static final Singleton getInstance(){
return SingletonHolder.INSTANCE;
}
}
该方法利用了静态内部类的特性实现了类似与懒汉式的单例模式
(单元素的)枚举实现
public enum Singleton{
INSTANCE;
}
枚举实现的单例已经简单到不能再简单了,可以直接使用 Singleton.INSTANCE 来获取单例。它虽然简单,但也是线程安全的实现方法,并且也是可序列化的。在 Effective Java 第二版里也推荐使用这种方法: 单元素的枚举类型已经成为实现 Singleton 的最佳方法
单例在 Java 中的应用
- Java.awt.Toolkit with getDefaultToolkit()
- Java.awt.Desktop with getDesktop()
- java.lang.Runtime
java.lang.Runtime 使用的单例(饿汉式,不涉及到线程安全):
public class Runtime{
private static Runtime currentRuntime = new Runtime();
public static Runtime getRuntime(){
return currentRuntime;
}
private Runtime(){}
//... 其他方法
}
参考
维基百科
StackExchange
使用枚举实现单例
Effective Java 第三条建议
单例模式(Singleton)小记的更多相关文章
- 设计模式之单例模式——Singleton
设计模式之单例模式--Singleton 设计意图: 保证类仅有一个实例,并且可以供应用程序全局使用.为了保证这一点,就需要这个类自己创建自己的对象,并且对外有 ...
- 【白话设计模式四】单例模式(Singleton)
转自:https://my.oschina.net/xianggao/blog/616385 0 系列目录 白话设计模式 工厂模式 单例模式 [白话设计模式一]简单工厂模式(Simple Factor ...
- ooad单例模式-Singleton
单例模式Singleton 主要作用是保证在Java应用程序中,一个类Class只有一个实例存在. 比如建立目录 ...
- iOS单例模式(Singleton)写法简析
单例模式的意思就是只有一个实例.单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例.这个类称为单例类. 1.单例模式的要点: 显然单例模式的要点有三个:一是某个类只能有一个实例: ...
- 浅谈设计模式--单例模式(Singleton Pattern)
题外话:好久没写blog,做知识归纳整理了.本来设计模式就是个坑,各种文章也写烂了.不过,不是自己写的东西,缺少点知识的存在感.目前还没做到光看即能记住,得写.所以准备跳入设计模式这个大坑. 开篇先贡 ...
- 设计模式之——单例模式(Singleton)的常见应用场景
单例模式(Singleton)也叫单态模式,是设计模式中最为简单的一种模式,甚至有些模式大师都不称其为模式,称其为一种实现技巧,因为设计模式讲究对象之间的关系的抽象,而单例模式只有自己一个对象,也因此 ...
- 设计模式之单例模式(Singleton Pattern)
单例模式 单例模式(Singleton Pattern)在java中算是最常用的设计模式之一,主要用于控制控制类实例的数量,防止外部实例化或者修改.单例模式在某些场景下可以提高系统运行效率.实现中的主 ...
- 设计模式(4) -- 单例模式(Singleton)
设计模式(4) -- 单例模式(Singleton) 试想一个读取配置文件的需求,创建完读取类后通过New一个类的实例来读取配置文件的内容,在系统运行期间,系统中会存在很多个该类的实例对象,也就是说 ...
- IOS单例模式(Singleton)
IOS单例模式(Singleton) 单例模式的意思就是只有一个实例.单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例.这个类称为单例类. 1.单例模式的要点: 显然单例模 ...
- java设计模式之 单例模式 Singleton
static 的应用 单例模式 Singleton 单例:保证一个类在系统中最多只创建一个实例. 好处:由于过多创建对象实例,会产生过多的系统垃圾,需要GC频繁回收,由于GC会占用较大的系统资源,所有 ...
随机推荐
- ZooKeeper与仲裁模式
为了让服务器之间可以通信,服务器间需要一些联系信息.理论上,服务器可以使用多播来发现彼此,但我们想让ZooKeeper集合支持跨多个网 络而不是单个网络,这样就可以支持多个集合的情况. 为了完成这些, ...
- SpringMVC配置过程中出现的问题!
<c:set var="ctx" value="${pageContext.request.contextPath}" />不起作用,原因是web. ...
- C# event 事件学习
C# event 事件学习 运行环境:Window7 64bit,.NetFramework4.61,C# 6.0: 编者:乌龙哈里 2017-02-26 章节: 简单事件编写 模拟 WPF 控件传递 ...
- HTML怎么让img 等比例缩放
在img标签里面只设置宽,不设置高,图片就会等比例缩放.
- 并发编程之IO模型比较和Selectors模块
主要内容: 一.IO模型比较分析 二.selectors模块 1️⃣ IO模型比较分析 1.前情回顾: 上一小节中,我们已经分别介绍过了IO模型的四个模块,那么我想大多数都会和我一样好奇, 阻塞IO和 ...
- Storm配置说明
配置项 配置说明 storm.zookeeper.servers ZooKeeper服务器列表 storm.zookeeper.port ZooKeeper连接端口 storm.local.dir s ...
- [cogs2638]数列操作ψ(双标记线段树)
题目大意:给定一个数列a,你需要支持的操作:区间and,区间or,询问区间最大值 解题关键: 1.双标记线段树,注意优先级(超时) 当涉及多重标记时,定义出标记的优先级,修改操作时用优先级高(先下放) ...
- 【总结整理】UGC内容
除了内容了产品,还有什么适合引入UGC? :引发讨论,诱导参与,然后促成销售. User Generated Content,也就是用户生成内容的意思. 购买类产品,内容催生购买 1.为用户购买提供思 ...
- 小程序本地资源无法通过 css 获取
background-image:可以使用网络图片,或者 base64,或者使用<image/>标签
- OCFS2 Fencing
OCFS2 FencingPosted on February 8, 2011 by Abdulhameed Basha I am very excited to start writing my e ...