设计模式—单例设计模式总结
来源:互联网 发布:windows.onload 编辑:程序博客网 时间:2024/05/23 14:58
看到一篇对单例描述很不错的文章,地址:https://www.2cto.com/kf/201704/631396.html
单例设计模式总结
单例模式简介
单例模式是应用最广泛的模式之一,在应用这个模式时,单例对象的类必须确保只有一个实例存在,避免产生多个对象消耗过多的资源。如在访问IO 和数据库时可以考虑使用单例模式。
单例模式的 UML 类图
Client - 高层客户端;
Singleton - 单例类;
实现单例模式的关键点
1). 构造函数私有化;
2). 通过一个静态方法或枚举返回单例类对象;
3). 确保单列类对象有且只有一个,尤其是在多线程环境下;
4). 确保单列类对象在反序列化是不会重新构建对象;
几种单列模式
1- 懒汉模式
public
class
Singleton
{
private
static
Singleton sInstance;
private
Singleton()
{
}
public
static
synchronized
Singleton getInstance()
{
if
(sInstance ==
null
)
{
sInstance =
new
Singleton();
}
return
sInstance;
}
}
优点:只有在使用时才会被实例化,在一定程度上节约了资源;
缺点:第一次加载时需要及时实例化,每次调用 getInstance() 方法都进行同步,造成不必要的同步开销。
这种模式一般不建议使用。
2- 饿汉模式
public
class
Singleton
{
private
static
Singleton sInstance =
new
Singleton();
private
Singleton() {}
public
static
synchronized
Singleton getInstance()
{
return
sInstance;
}
}
优点:类加载时实例化,避免了线程不同步问题;
缺点:无法对singleton实例做延迟加载。
3 - Double Check Lock(DCL) 模式
public
class
Singleton
{
// private static Singleton sInstance = null;
//JDK 1.5 以后写法
private
static
volatile
Singleton sInstance =
null
;
private
Singleton() {}
public
static
Singleton getInstance()
{
if
(sInstance ==
null
)
{
synchronized
(Singleton.
class
)
{
if
(sInstance ==
null
)
{
sInstance =
new
Singleton();
}
}
}
return
sInstance;
}
}
为什么 JDK1.5以后版本改变了写法呢?
这是因为 sInstance = new Singleton() 语句并非是一个原子操作,这句代码最终会被编译成多条汇编指令,大致做了3件事情:
(1)给 Singleton 的实例分配内存;
(2)调用 Singleton() 的构造函数,初始化成员字段;
(3)将 sInstance 对象指向分配的内存地址(此时 sInstance 就不是 null了);
由于 Java 编译器允许处理器乱起执行,以及 JDK1.5之前 JMM(Java Memory Model,即 Java 内存模型)中 Cache、寄存器到主内存会写顺序的规定,(2)和(3)的顺序是无法保证的,执行顺序可能是 1- 2 - 3也可能是 1 - 3 - 2,如果是后者,假设线程A在(3)执行完毕,(2)未执行时,此时被切换到线程B上,这时 sInstance 因为线程A已经执行过了(3),sInstance 已经是非空了,线程B直接获取 sInstance,再使用时就会出错,这种错误难以跟踪及发现,所以在 JDK1.5版本之后,调整了 JVM 具体化了 volatile 关键字,因此将 sInstance 的定义改成了
private static volatile Singleton mInstance = null;
就可以保证 sInstance 对象每次都是从主内存中读取。
优点:资源利用率高,第一次执行 getInstance() 时单例对象才会被实例化,效率高;
缺点:第一次加载时反应稍慢,也由于 Java 内存模型的原因偶尔会失败。
DCL 模式是使用最多的单例实现方式。
4 - 静态内部类模式
public
class
Singleton
{
private
Singleton() {}
public
static
Singleton getInstance()
{
return
SingletonHolder.sInstance;
}
private
static
class
SingletonHolder
{
private
static
final
Singleton sInstance =
new
Singleton();
}
}
当第一次加载 Singleton 类时并不会初始化 sInstance ,只有在第一次调用 getInstance() 方法时才会初始化 sInstance 。
优点: 确保线程安全并保证单例对象的唯一性。
推荐使用此单例模式实现方式。
5 - 枚举单例模式
public
enum
Singleton
{
INSTANCE;
public
void
log()
{
//....
}
}
优点: 写法简单,线程安全,并且在任何情况下它都是一个单列。
为什么说枚举单例是在任何情况下都是一个单列呢?那就是反序列化。
1至4的单例模式中,在反序列化情况下会出现重新创建对象的情况,反序列化时依然可以通过特殊的途径去创建一个类的实例,相当于调用该类的构造函数。上述实例中如要杜绝单例对象被反序列化时重新生成对象,必须加入如下的方法:
private
Object readResolve()
throws
ObjectStreamException
{
return
sInstance;
}
在 readResolve() 方法中将 sInstance 对象返回,而不是默认的重新生成一个新的对象,对应枚举却不存在这个问题,因此即使反序列化也不会重新生成一个新的实例。
总结 无论哪种方式实现的单例模式,核心原理都是将构造函数私有化,并且通过静态方法获取一个唯一的实例,获取过程中必须保证线程安全、防止反序列化导致重新生成实例对象的问题。
- 设计模式总结—单例模式
- 设计模式总结—单例模式
- Java 设计模式—单例设计模式总结
- 设计模式—单例设计模式总结
- 单例设计模式总结
- 单例设计模式总结
- 单例设计模式总结
- 单例设计模式总结
- [总结]设计模式之-单例模式
- 设计模式总结之单例模式
- 设计模式总结-单例模式
- 设计模式-单例模式总结
- 设计模式总结之单例模式
- 设计模式之单例模式总结
- 设计模式之单例模式总结
- Android设计模式 -- 单例模式总结
- 设计模式之---单例模式总结
- 设计模式—单例设计模式
- ViewPager中嵌套activity页面
- IO流--练习
- 机器学习基础概念与算法
- UVa10269
- 深入理解Java虚拟机(一)-----Java内存区域和内存溢出
- 设计模式—单例设计模式总结
- Android组件学习笔记(ListView结构操作)
- 淘宝 NPM 镜像
- MySql5.7 建立全文索引
- 科普文章--解剖Google
- struts自定义拦截器及其执行流程
- 笔记三:嵌入式板子读写寄存器的方法
- 让你快乐的20个习惯
- php正则表达式详解