单例模式

1. 单例模式解析

  • 单例所指的就是单个实例,也就是说要保证一个类仅有一个实例。
  • 单例模式有以下的特点:
    • ①单例类只能有一个实例
    • ②单例类必须自己创建自己的唯一实例
    • ③单例类必须给所有其他对象提供这一实例

2. 单例模式示例

  • 以下示例都是在同一个JVM中实现的,在分布式环境下如何保证分布在不同机器上的整个应用只有一个实例是更复杂的话题。

2.1 简单单例模式

  • 为了实现上面的特点,有以下基本实现:
/**
* 单例模式示例:
* - 简单单例模式
*/
public class Singleton{
//变量是私有的,外界无法访问
private static Singleton singleton = new Singleton();
//other fields... //Singleton类只有一个构造方法,被private修饰的, 客户对象无法创建该类实例。
private Singleton(){ } //实现全局访问点
public static Singleton getInstance(){
return singleton;
}
//other motheds...
}
  • 如果该实例需要比较复杂的初始化过程时,可以把这个过程应该写在static{……}代码块中
  • 此实现是线程安全的,当多个线程同时去访问该类的getInstance( ) 方法时,不会初始化多个不同的对象,这是因为,JVM在加载此类时,对于static属性的初始化只能由一个线程执行且仅一次。

2.2 延迟创建的单例模式

  • 上面的单例模式会在类加载的时候就初始化实例,如果这样的单例较多,会使程序初始化效率低下。
  • 为了在类的实例第一次使用时才初始化,我们可以把单例的实例化过程放到getInstance()方法中,而不在加载类时预先创建。
/**
* 单例模式示例:
* - 延迟创建的单例模式
*/
public class UnThreadSafeSingleton{
//变量是私有的,外界无法访问
private static UnThreadSafeSingleton singleton = null;
//other fields... //UnThreadSafeSingleton类只有一个构造方法,被private修饰的, 客户对象无法创建该类实例。
private UnThreadSafeSingleton(){ } //实现全局访问点
public static UnThreadSafeSingleton getInstance(){
//在这里实现延迟创建,但是下面的三行不是线程安全的,
//在高并发环境下会生成多个不同的该类实例
//在没有自动内存回收机制的语言平台中,容易内存泄露
if(singleton ==null){
singleton = new UnThreadSafeSingleton();
}
return singleton;
}
//other motheds...
}
  • 为了解决上面线程安全的问题,我们可以给此方法加synchronized关键字,来保证多线程访问都只会实例化一次。

Double-Check Locking

/**
* 单例模式示例:
* - 线程安全的延迟创建的单例模式
*/
public class DoubleCheckSingleton{
//变量是私有的,外界无法访问
//volatile具有synchronized的可见性特点,也就是说线程能够自动发现volatile变量的最新值。
//这样,如果instatnce实例化成功,其他线程便能立即发现
private volatile static DoubleCheckSingleton singleton = null;
//other fields... //DoubleCheckSingleton类只有一个构造方法,被private修饰的, 客户对象无法创建该类实例。
private DoubleCheckSingleton(){ } //实现全局访问点
public static DoubleCheckSingleton getInstance(){
//两次检查是为了防止两个线程都进行到同步块的时候,可能会创建两个实例
if(singleton ==null){
synchronized (DoubleCheckSingleton.class){
if(singleton ==null){ //这里如果不检查还是会生成两个实例
singleton = new DoubleCheckSingleton();
}
}
return singleton;
}
//other motheds...
}

2.3 Initialization on demond holder

  • 另一种实现延迟加载且线程安全的实例化方法
/**
* 单例模式示例:
* - 延迟加载单例模式
*/
public class LazyLoadedSingleton{
//other fields... //LazyLoadedSingleton类只有一个构造方法,被private修饰的, 客户对象无法创建该类实例。
private LazyLoadedSingleton(){ } private static class LazyHolder{
//变量是私有的,外界无法访问
//holds zhe singleton class
private static LazyLoadedSingleton singleton = new LazyLoadedSingleton(); }
/**
* 只有当第一次调用该方法时,JVM才会加载LazyHolder类,然后才初始化static的singleton
* 这样即保证了线程安全,又实现了延迟加载
*/
public static LazyLoadedSingleton getInstance(){
return LazyHolder.singleton;
}
//other motheds...
}

2. spring的单例模式

  • 参考文档:

    • 该文仅介绍spring的单例模式:spring 的单例模式
    • 介绍原理:Spring的单例模式底层实现
    • 对spring中单例模式线程安全的讨:Spring中Singleton模式的线程安全
    • 针对上面的单例模式有以下说法:
      • 延迟加载的单例模式可以称为懒汉式单例
      • 非延迟加载的称为饿汉式单例
    • 饿汉式单例在自己被加载时就将自己实例化,如果从资源利用效率角度来讲,比懒汉式单例类稍差些。但是从速度和反应时间角度来讲,则比懒汉式要稍好些。
  • 解释参考文档上的一句话:由于构造函数是私有的,因此该类不能被继承
  • 上面的单例模式都不能被继承,所以spring采用的是另一种单例模式,称为单例注册表

2.1 单例注册表方法

  • Spring对单例的底层实现,到底是饿汉式单例还是懒汉式单例呢?呵呵,都不是。Spring框架对单例的支持是采用单例注册表的方式进行实现的。

    • 以下参考文章分析的源代码应该是spring比较老的版本,我参考现在比较新的4.3.2版本,有些不同,但是原理应该是一样的。下面的源代码是spring-beans-4.3.2-REALEASE版本的。
    • 详情参考:Spring的单例模式底层实现
    • Spring对bean实例的创建是采用单例注册表的方式进行实现的,而这个注册表的缓存是HashMap对象,如果配置文件中的配置信息不要求使用单例,Spring会采用新建实例的方式返回对象实例
public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {
......
public Object getBean(String name) throws BeansException {
return this.doGetBean(name, (Class)null, (Object[])null, false);
}
.....
protected <T> T doGetBean(String name, Class<T> requiredType, final Object[] args, boolean typeCheckOnly) throws BeansException {
//对传入的Bean name稍做处理,防止传入的Bean name名有非法字符(或者做转码)
final String beanName = this.transformedBeanName(name);
Object sharedInstance = this.getSingleton(beanName);
Object bean;
//从单例注册表中查找,如果存在,就获得了单例
if(sharedInstance != null && args == null) {
......
bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, (RootBeanDefinition)null);
} else {
......
//否则
try {
//取得bean的定义
final RootBeanDefinition ex1 = this.getMergedLocalBeanDefinition(beanName);
......
//如果是单例,做如下处理
if(ex1.isSingleton()) {
sharedInstance = this.getSingleton(beanName, new ObjectFactory() {
...... });
bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, ex1);
} else if(ex1.isPrototype()) {
......
//如果是prototype。创建一个bean
Object var25;
try {
this.beforePrototypeCreation(beanName);
var25 = this.createBean(beanName, ex1, args);
} finally {
this.afterPrototypeCreation(beanName);
}
......
bean = this.getObjectForBeanInstance(var25, name, beanName, ex1);
} else {
......
bean = this.getObjectForBeanInstance(var28, name, beanName, ex1);
}
} catch (BeansException var23) {
this.cleanupAfterBeanCreationFailure(beanName);
throw var23;
}
}
if(requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {
......
} else {
return bean;
}
}

设计模式--单例模式(Singleton pattern)及应用的更多相关文章

  1. 浅谈设计模式--单例模式(Singleton Pattern)

    题外话:好久没写blog,做知识归纳整理了.本来设计模式就是个坑,各种文章也写烂了.不过,不是自己写的东西,缺少点知识的存在感.目前还没做到光看即能记住,得写.所以准备跳入设计模式这个大坑. 开篇先贡 ...

  2. 设计模式之单例模式(Singleton Pattern)

    单例模式 单例模式(Singleton Pattern)在java中算是最常用的设计模式之一,主要用于控制控制类实例的数量,防止外部实例化或者修改.单例模式在某些场景下可以提高系统运行效率.实现中的主 ...

  3. 乐在其中设计模式(C#) - 单例模式(Singleton Pattern)

    原文:乐在其中设计模式(C#) - 单例模式(Singleton Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 单例模式(Singleton Pattern) 作者:weba ...

  4. 设计模式系列之单例模式(Singleton Pattern)——确保对象的唯一性

    模式概述 模式定义 模式结构图 饿汉式单例与懒汉式单例 饿汉式单例 懒汉式单例 模式应用 模式在JDK中的应用 模式在开源项目中的应用 模式总结 主要优点 适用场景 说明:设计模式系列文章是读刘伟所著 ...

  5. 【设计模式】单例模式 Singleton Pattern

    通常我们在写程序的时候会碰到一个类只允许在整个系统中只存在一个实例(Instance)  的情况, 比如说我们想做一计数器,统计某些接口调用的次数,通常我们的数据库连接也是只期望有一个实例.Windo ...

  6. 二十四种设计模式:单例模式(Singleton Pattern)

    单例模式(Singleton Pattern) 介绍保证一个类仅有一个实例,并提供一个访问它的全局访问点. 示例保证一个类仅有一个实例. Singleton using System; using S ...

  7. 抽象工厂(Abstract Factory),工厂方法(Factory Method),单例模式(Singleton Pattern)

    在谈工厂之前,先阐述一个观点:那就是在实际程序设计中,为了设计灵活的多态代码,代码中尽量不使用new去实例化一个对象,那么不使用new去实例化对象,剩下可用的方法就可以选择使用工厂方法,原型复制等去实 ...

  8. 十次艳遇单例设计模式(Singleton Pattern)

    1.引言 单例设计模式(Singleton Pattern)是最简单且常见的设计模式之一,在它的核心结构中只包含一个被称为单例的特殊类.通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访 ...

  9. 设计模式 单例模式(Singleton) [ 转载2 ]

    设计模式 单例模式(Singleton) [ 转载2 ] @author java_my_life 单例模式的结构 单例模式的特点: 单例类只能有一个实例. 单例类必须自己创建自己的唯一实例. 单例类 ...

  10. 设计模式 单例模式(Singleton) [ 转载 ]

    设计模式 单例模式(Singleton) [ 转载 ] 转载请注明出处:http://cantellow.iteye.com/blog/838473 前言 懒汉:调用时才创建对象 饿汉:类初始化时就创 ...

随机推荐

  1. spring-boot开发:使用内嵌容器进行快速开发及测试

    一.简述一下spring-boot微框架 1.spring-boot微框架是什么? 大家都知道,在使用spring框架进行应用开发时需要很多*.xml的初始化配置文件,而springBoot就是用来简 ...

  2. 关于angular-route后获取路由标签的一些问题

    要实现angular路由,我们需要用到angular.js和angular-route.js 在接入网络的情况下,很多网站都可以下载到这个文件. 然后呢,将文件引入到你的HTML中,然后是基础格式 h ...

  3. cp的用法

    1.cp的功能 拷贝一个或多个文件(或目录)到目的地 2.例子 1)一次拷贝多个源文件到目的地#cp /mnt/hgfs/DOC/{1,2,3,4,5}.txt /root/ldj 2)只拷贝链接文件 ...

  4. grid表格选择模式

    selModel: { // type: 'checkboxmodel', type: 'cellmodel', // mode: 'SIMPLE', mode: 'SINGLE', checkOnl ...

  5. LoadRunner11_录制Oracle数据库脚本

    [oracle环境] ①oracle:无需在本地安装oracle,但是oracle的odbc驱动一定要装:(我的安装路径为 D:\oracle ).安装好后在环境变量 " Path &quo ...

  6. Linux命令 文件备份归档恢复

    cp [功能说明] 文件的备份 英文xxxx  #cp命令将源文件复制到另外安全的地方,复制的文件和源文件是两个相互独立的文件,对认识一个文件的操作不影响另一个文件,但与符号链接文件中的硬链接是有区别 ...

  7. Codeforces Round #419 (Div. 2)

    1.题目A:Karen and Morning 题意: 给出hh:mm格式的时间,问至少经过多少分钟后,该时刻为回文字符串? 思路: 简单模拟,从当前时刻开始,如果hh的回文rh等于mm则停止累计.否 ...

  8. 并发编程(一):从头到脚解读synchronized

    一.目录 1.多线程启动方式 2.synchronized的基本用法 3.深度解析synchronized 4.同步方法与非同步方法是否能同时调用? 5.同步锁是否可重入(可重入锁)? 6.异常是否会 ...

  9. Git操作简介

    一 概述 1.什么是Git? Git是分布式版本控制系统. 2.集中式与分布式对比 在集中式版本控制系统中,版本库集中在中央服务器上,每次工作时都需要先从中央服务器获取最新版本,修改后,再推送到中央服 ...

  10. ASP.NET MVC Bundling and RequireJS

    关于ASP.NET MVC Bundling and RequireJS的取舍问题,最近比较困惑,我希望有一种方式可以结合两者的优点.作为.NET程序员,难道你没有过这方面的困惑吗? 因为我感觉各自都 ...