设计模式——单例模式
Posted 唐杠杠
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式——单例模式相关的知识,希望对你有一定的参考价值。
设计模式——单例模式
概念:
单例模式是设计模式中很常见的一种模式,各种框架,系统中都有应用。
其定义是单例对象的类只能允许一个实例存在。在许多时候整个系统只需要拥有一个全局对象,这样有利于我们系统系统整体的行为。
实现主要是以下两个步骤:
- 将该类的构造方法定义为私有方法,这样其他处的代码就无法通过调用该类的构造方法来实例化该类的对象,只有通过该类提供的静态方法来得到该类的唯一实例;
- 在该类内提供一个静态方法,当我们调用这个方法时,如果该类的引用不为空,就返回该类的引用,如果该类的引用为空,就创建该类的实例,并赋值给该类的引用。
- 单例模式可分为有状态的和无状态的。有状态的单例对象一般也是可变的单例对象,多 个单态对象在一起就可以作为一个状态仓库一样向外提供服务。没有状态的单例对象也就是 不变单例对象,仅用做提供工具函数。
适用场景:
- 需要频繁实例化然后销毁;
- 需要生成唯一序列的环境;
- 实例化耗时过多,但是又经常用到;
- 资源互相通信的环境
实现
饿汉式
public class HungryMod {
//私有化构造方法
private HungryMod() {
}
// 指向自己实例的私有静态引用
private static HungryMod mod = new HungryMod();
//静态工厂方法,提供给外部调用获得实例
public static HungryMod getInstance() {
return mod;
}
}
类的加载是按需加载,且加载一次。因此,在上述类被加载时,就是实例化一个对象指向自己的引用;而且类在整个生命周期只会被加载一次,因此只会创建一个实例。
优缺点
优点:
写法简单,在类加载时就完成了实例化,避免线程同步问题
缺点:
没有延迟加载,因为这个实例是在类的加载时就创建了,如果没使用就造成了内存浪费
懒汉式
public class LazyMod {
// 私有化构造方法
private LazyMod(){
}
// 指向自己的静态实例
private static LazyMod mod=null;
// 提供给外部访问的静态方法
public static LazyMod getInstance(){
if (mod==null){
mod=new LazyMod();
}
return mod;
}
}
懒汉式就是延迟加载的,在真正使用的时候才会去创建一个新的实例,指向自己的引用
优缺点
优点:
延迟加载,避免内存的浪费
缺点:
if语句在多线程下,就可能出现多个实例的问题,所以多线程不适用
所以可以在懒汉模式下的静态方法上加一个锁
public synchronized static LazyMod getInstance(){
if (mod==null){
mod=new LazyMod();
}
return mod;
}
线程安全的懒汉模式——这样虽然解决了线程安全问题,但是synchronized效率低。
双重加锁机制
public class DoubleLockMod {
// 空指向
private static DoubleLockMod mod = null;
// 私有化构造函数
private DoubleLockMod() {
}
public static DoubleLockMod getInstance() {
// 第一次检查instance是否被实例化出来,如果没有进入if块
if (mod == null) {
// 类锁
synchronized (DoubleLockMod.class) {
// 某个线程取得了类锁,实例化对象前第二次检查instance是否已经被实例化出来,如果没有,才最终实例出对象
if (mod == null) {
mod = new DoubleLockMod();
}
}
}
return mod;
}
}
这样就解决了懒汉式下的线程问题,也解决了效率问题,这是最优秀的方案
总结
单例模式在框架,系统中都很常见,也是简单的一种设计模式。当然单例模式还有个邪恶论,单例模式在java系统中存在很多陷阱和假象......
参考
1、高洪岩,Java多线程编程核心技术,机械工业出版社
以上是关于设计模式——单例模式的主要内容,如果未能解决你的问题,请参考以下文章