设计模式(4) -- 单例模式(Singleton)
设计模式(4) -- 单例模式(Singleton)
试想一个读取配置文件的需求,创建完读取类后通过New一个类的实例来读取配置文件的内容,在系统运行期间,系统中会存在很多个该类的实例对象,也就是说系统中会同时存在多份配置文件的内容,这样会严重浪费内存资源。这样需要实现:在一个系统运行期间,只要一个类实例就可以了。
单例模式的定义:保证一个类仅有一个实例,并提供一个访问它的全局访问点。
现在一个类能够被创建多个实例,问题的根源在于类的构造方法是公开的,也就是可以让类的外部通过构造方法创建多个实例。换句话说,只要类的构造方法能让类的外部访问,就没有办法去控制外部来创建这个类的实例个数。
要想控制一个类只被创建一个实例,那么首要的问题就是要把创建实例的权限收回来,让类自身来负责自己类实例的创建工作,然后由这个类来提供外部可以访问这个类实例的方法,这就是单例模式的实现方式。
在Java中,单例模式分为两种,懒汉式和饿汉式。
懒汉式:
public classSingletonLan {
privatestaticSingletonLan uniqueInstance = null;
privateSingletonLan(){
}
publicstaticsynchronizedSingletonLan getInstance(){
if(uniqueInstance==null){
uniqueInstance = new SingletonLan();
}
return uniqueInstance;
}
publicvoidsingletonOPeration(){
}
privateString singletonData;
publicStringgetSingletonData(){
return singletonData;
}
}
饿汉式:
public classSingletonE {
private static SingletonE uniqueInstance= newSingletonE();
privateSingletonE(){
}
publicstaticSingletonEgetInstance(){
return uniqueInstance;
}
publicvoidsingletonOPeration(){
}
privateString singletonData;
publicString getSingletonData(){
return singletonData;
}
}
Java里面实现的单例是一个虚拟机范围。因为装载类的功能是虚拟机的,所以一个虚拟机在通过自己的ClassLoader装载饿汉式实现单例类的时候就会创建一个类的实例。这就意味着如果一个虚拟机里面有很多个ClassLoader,而且这些ClassLoader都装载某个类的话,就算这个类是单例,它也会产生很多个实例。当然,如果一个机器上有多个虚拟机,那么每个虚拟机里面都应该至少有一个这个类的实例,也就是说整个机器上就有很多个实例,更不会是单例了。
单例模式的精粹是static变量在类装载的时候进行初始化;多个实例的static变量会共享同一块内存区域。
单例模式有一种应用叫延迟加载(Lazy Load):一开始不需要加载资源或者数据,一直等,等到马上要使用这个资源或者数据的时候才去加载。
利用缓存来实现单例模式:
import java.util.HashMap;
import java.util.Map;
public classSingletonCache {
private final static String DEFAULT_KEY="One";
private static Map<Object,SingletonCache> map = newHashMap<Object,SingletonCache>();
private SingletonCache(){
}
public static SingletonCache getInstance(){
SingletonCache instance = (SingletonCache)map.get(DEFAULT_KEY);
if(instance==null){
instance = new SingletonCache();
map.put(DEFAULT_KEY,instance);
}
return instance;
}
}
从线程安全上讲,懒汉式是线程不安全的,饿汉式是线程安全的(虚拟机保证只会加载一次,在装载类的时候是不会发生并发的),但是加了synchronized关键字的懒汉式是线程安全的,只是效率下降了。
可以使用双重检查加锁机制,指的是并不是每次进入getInstance方法都需要同步,而是先不同步,进入方法过后,先检查实例是否存在,如果不存在才进入下面的同步块,这是第一重检查。进入同步块后,再次检查实例是否存在,如果不存在,就在同步的情况下创建一个实例,这是第二重检查。这样一来,就只需要同步一次了。
双重检查加锁机制的实现用到关键字volatile,意思是被volatile修饰的变量的值,将不会被本地线程缓存,所有对该变量的读写都是直接操作共享内存,从而确保多个线程能正确的处理该变量。由于volatile关键字可能会屏蔽虚拟机中一些必要的代码优化,所以运行效率并不是很高。
public classSingletonVolatile {
privatevolatilestaticSingletonVolatile instance = null;
privateSingletonVolatile(){
}
publicstaticSingletonVolatilegetInstance(){
if(instance== null){
synchronized(SingletonVolatile.class){
if(instance==null){
instance = newSingletonVolatile();
}
}
}
return instance;
}
}
Lazyinitialization holder class模式综合实现了延迟加载和线程安全。在类加载的时候不去初始化对象。
public classSingletonClass {
privatestaticclassSingletonHolder{
private staticSingletonClass instance = newSingletonClass();
}
privateSingletonClass(){
}
publicstaticSingletonClassgetInstance(){
return SingletonHolder.instance;
}
}
据说单元素的枚举类型已经成为实现Singleton的最佳方法。
设计模式(4) -- 单例模式(Singleton)的更多相关文章
- 设计模式之单例模式——Singleton
设计模式之单例模式--Singleton 设计意图: 保证类仅有一个实例,并且可以供应用程序全局使用.为了保证这一点,就需要这个类自己创建自己的对象,并且对外有 ...
- 乐在其中设计模式(C#) - 单例模式(Singleton Pattern)
原文:乐在其中设计模式(C#) - 单例模式(Singleton Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 单例模式(Singleton Pattern) 作者:weba ...
- 【设计模式】单例模式-Singleton
[设计模式]单例模式-SingletonEnsure a class has only one instance, and provide a global point to access of it ...
- 设计模式之——单例模式(Singleton)的常见应用场景
单例模式(Singleton)也叫单态模式,是设计模式中最为简单的一种模式,甚至有些模式大师都不称其为模式,称其为一种实现技巧,因为设计模式讲究对象之间的关系的抽象,而单例模式只有自己一个对象,也因此 ...
- 设计模式之单例模式(Singleton Pattern)
单例模式 单例模式(Singleton Pattern)在java中算是最常用的设计模式之一,主要用于控制控制类实例的数量,防止外部实例化或者修改.单例模式在某些场景下可以提高系统运行效率.实现中的主 ...
- 设计模式一: 单例模式(Singleton)
简介 单例模式是属于创建型模式的一种(另外两种分别是结构型模式,行为型模式).是设计模式中最为简单的一种. 英文单词Singleton的数学含义是"有且仅有一个元素的集合". 从实 ...
- 设计模式之——单例模式(Singleton)的常见应用场景(转):
单例模式(Singleton)也叫单态模式,是设计模式中最为简单的一种模式,甚至有些模式大师都不称其为模式,称其为一种实现技巧,因为设计模式讲究对象之间的关系的抽象,而单例模式只有自己一个对象,也因此 ...
- java设计模式之 单例模式 Singleton
static 的应用 单例模式 Singleton 单例:保证一个类在系统中最多只创建一个实例. 好处:由于过多创建对象实例,会产生过多的系统垃圾,需要GC频繁回收,由于GC会占用较大的系统资源,所有 ...
- 【设计模式】单例模式 Singleton Pattern
通常我们在写程序的时候会碰到一个类只允许在整个系统中只存在一个实例(Instance) 的情况, 比如说我们想做一计数器,统计某些接口调用的次数,通常我们的数据库连接也是只期望有一个实例.Windo ...
随机推荐
- 不同的路径 II
class Solution { public: /** * @param obstacleGrid: A list of lists of integers * @return: An intege ...
- HTML5-javascript屏幕旋转事件:onorientationchange
屏幕旋转事件:onorientationchange 添加屏幕旋转事件侦听,可随时发现屏幕旋转状态(左旋.右旋还是没旋) 判断屏幕是否旋转 function orientationChange() { ...
- 关于手机端CSS Sprite图标定位的一些领悟
今天在某个群里面闲逛,看见一个童鞋分享了一个携程的移动端的页面.地址这里我也分享下吧:http://m.ctrip.com/html5/在手机端我都很少用雪碧图合并定位图标,用的比较多就是用字体图标来 ...
- php 函数 array_slice
array_slice array_slice -- 从数组中取出一段 <?php$input = array("a", ); // returns "c ...
- OOS升级服务
给我们的应用程序做个版本更新服务,展示一个安装程序如何实现自动更新. //服务组,添加需要的任何服务 public enum ServerEnum { AutoupdateService,//自动升级 ...
- 学习Swift -- 构造器(下)
构造器(下) 可失败的构造器 如果一个类,结构体或枚举类型的对象,在构造自身的过程中有可能失败,则为其定义一个可失败构造器,是非常有必要的.这里所指的“失败”是指,如给构造器传入无效的参数值,或缺少某 ...
- VC6.0中重载操作符函数无法访问类的私有成员
整理日: 2015年03月18日 在 C++ 中,操作符(运算符)可以被重载以改写其实际操作.同时我们可以定义一个函数为类的朋友函数(friend function)以便使得这个函数能够访问类的私有成 ...
- (转载)KL距离,Kullback-Leibler Divergence
转自:KL距离,Kullback-Leibler Divergence KL距离,是Kullback-Leibler差异(Kullback-Leibler Divergence)的简称,也叫做相对 ...
- [BZOJ 1112] [POI2008] 砖块Klo 【区间K大】
题目链接:BZOJ - 1112 题目分析 枚举每一个长度为k的连续区间,求出这个区间的最优答案,更新全局答案. 可以发现,这个区间的所有柱子最终都变成这k个数的中位数时最优,那么我们就需要查询这个区 ...
- Phonegap 3.0 拍照 出错的说明
在官方3.0 提供的摄像机操作例子是不成功的,因为该例子没有说明摄像机操作需要添加Plugin. 添加插件方法(安装cordova3.0时必须使用官方命令行方式,通过nodejs安装,且装上了git) ...