常用设计模式之单例模式
来源:互联网 发布:重庆地区网络推广 编辑:程序博客网 时间:2024/05/20 02:27
1.问题描述
在一个系统运行期间,某个类只需要一个实例运行就可以,该如何实现呢?
2.模式定义
保证一个类仅有一个实例,并提供一个访问它的全局访问点。
3.解决思路
控制一个类只创建一个实例,首先就是要把类创建的权限收回,让类负责自己实例的创建,然后再提供外部访问实例的方法。代码如下所示:
public class SingleInstance{ private static SingleInstance instance; private SingleInstance(){} private static SingleInstance getInstance(){ if(instance == null) instance = new SingleInstance(); return instance; } ......}4.线程安全
上述代码创建了可延迟初始化的单例,然而在高并发的环境中,getInstance()方法返回了多个指向不同的实例。以下给出两个线程并发访问getInstance()方法时的一种情况:
Thread1
if(instance == null) instance = new SingleInstance();return instance;Thread2
if(instance == null) instance = new SingleInstance();return instance;如果这两个线程按照上述步骤执行,当还没有创建单例对象,Thread1和Thread2都会进入创建单例实例的代码块分别创建实例。此时,Thread1创建了一个实例对象,但是Thread2此刻已无法知道,于是继续创建一个新的单例对象,导致这两个线程持有的实例并非同一个。
为解决这个问题,给此方法添加synchronized关键字,代码如下:
public class ThreadSafeSingleInstance{ public static synchronized ThreadSafeSingleInstance getInstance(){ if(instance == null) instance = new ThreadSafeSingleInstance(); return instance;}}虽然通过synchronized实现了多线程的安全访问,但是在多线程高并发的情况下,会使得性能大不如前。经分析,不难发现,使用synchronized对整个getInstance()方法进行同步是没有必要的,我们只要保证实例化这个对象的那段逻辑被一个线程执行就可以了,而返回引用的那段代码是没必要同步的。实现如下:
public DoubleCheckSingleInstance{ private volatile static DoubleCheckSingleInstance instance = nul; //构造函数 public static DoubleCheckSingleInstance getInstance(){ if(instance == null){ synchronized(DoubleCheckSingleInstance.class){ if(instance == null) instance = new DoubleCheckSingleInstance(); } } return instance; }}代码注解:
在getInstance()方法里,首先判断此实例是否已经被创建了,如果还没有创建,使用synchronized同步实例化代码块。在同步代码块里,还需要再次检查是否已经创建了此类的实例,如没有第二次检查,当有两个线程同时进入该方法,同样会出现生成两个实例对象。
5.场景假设
假设有两个线程,Thread1和Thread2,它们执行以下步骤:
(1)Thread1发现instance没有被实例化,它获得锁,并去实例化此对象,JVM容许在没有完全实例化完成时,instance变量就指向此实例,因为这些步骤可以是次序颠倒的,此时instance == null为false
(2)在初始化完成之前,Thread2进入此方法,发现instance已经不为null了,Thread2便认为该实例已经初始化完成了,使用这个未完成初始化的实例对象,则很可能引起系统的崩溃。
如要设计使用线程安全的延迟的单例初始化,可使用Initialization on demand holder模式。代码如下:
public class LazyLoadedSingleInstance{ private LazyLoadedSingleInstance(){} private static class LazyHolder{ private static final LazyLoadedSingleInstance singletonInstance = new LazyLoadedSingleInstance(); } public static LazyLoadedSingleInstance getInstance(){ return LazyHolder.singletonInstance; }}代码注解:
当JVM加载LazyLoadedSingleInstance类时,由于该类没有static属性,所以加完完成后便即可返回。只有第一次调用getInstance()方法时,JVM才会加载LazyHolder类,由于它包含一个static属性singletonInstance,所以会首先初始化这个变量,此过程并不会出现并发问题,这样即实现了一个既保证线程安全又支持延迟加载的单例模式。
6.应用场景
如果要保证系统里一个类最多只能存在一个实例时,我们就需要单例模式。例如缓存池、数据库连接池、线程池,一些应用服务实例等。
- 常用设计模式之单例模式
- 常用设计模式之单例模式
- 【设计模式】常用Java设计模式之单例模式
- Java常用设计模式之单例模式(Singleton)
- IOS常用设计模式之---单例模式
- Unity常用设计模式之单例模式
- Java中常用的设计模式之单例模式
- java 常用设计模式------单例模式
- 常用的设计模式----单例模式
- 设计模式之 单例设计模式
- 设计模式之 单例设计模式
- 设计模式之单例设计模式
- 设计模式之-----------单例设计模式
- 设计模式之:单例设计模式
- 设计模式之单例设计模式
- 设计模式之单例设计模式
- 设计模式之单例设计模式
- 设计模式之单例设计模式
- Static用法总结
- 批处理 同时运行多个程序、关闭多个程序
- Android Develop Training中文翻译05《Building a Simple User Interfa
- 图解SQL的inner join、left join、right join、full outer join、union、union all的区别
- easyui datagrid的toolbar如何添加输入框或自定义控件
- 常用设计模式之单例模式
- calcHist的使用
- 支付宝接口调用
- php变量作用域 总结
- 关于树脂碳带、亚银纸打印条码(注意事项)
- 创建独立的Firefox profile
- 谈谈finally,final,finalize的用法
- 正则表达式实例(c语言)
- JS 禁用畫面驗證控件