设计模式(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 ...
随机推荐
- 引入的iframe是跨域的, 如何控制其高度
前提是你有编辑这个跨域的iframe的权限!! 1. main-domain.html (main display HTML) <!DOCTYPE html> <html> & ...
- ES5中数组新增的方法说明
一.前言-索引 ES5中新增的不少东西,了解之对我们写JavaScript会有不少帮助,比如数组这块,我们可能就不需要去有板有眼地for循环了. ES5中新增了写数组方法,如forEach (js v ...
- js获取上传文件信息并及时查看
<form id="picForm" name="picForm" method="post" enctype="mult ...
- javascript删除目标标签
<script> window.onload=function(){ var odiv=document.getElementById("content"); // ...
- JavaScript学习心得(四)
条件语句 任何事物非真即假. 在JavaScript中,条件判断以下情况为假: false NaN 0 空串 null undefined 在使用相等运算符时,建议将数字写在相等运算符的左边.全等比较 ...
- ubuntu 安装apache2,mysql,php5,phpmyadmin等软件
1.安装apache2 sudo apt-get install apache2 输入Y回车 apache2 安装完成 检测:在浏览器输入localhost 出现It works则成功. 2. ...
- Attributes(1):反射Attribute并输出
using System; using System.Reflection; using System.Text; namespace Attribute01 { class Program { ...
- django框架的网站发布后设置是否允许被别人iframe引用
例如: <iframe src="http://127.0.0.1:8008" style="width:100%;height:400px;">& ...
- WPF之 XAML集合项简单演示
我们直接通过xaml文件演示一个简单的xaml集合项: <Window x:Class="WPF_XAML集合项.MainWindow" xmlns="http:/ ...
- python随机数
前提:需要导入random模块 >>>import random 1.random.random random.random()用于生成一个0到1的随机符小数: 0 <= n ...