单例模式

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. 【原创】Ajax的用法总结

    一.什么是Ajax Ajax英文全称为“ Asynchr JavsScript and XML”(异步的JavaScript和XML),是一种创建 交互式网页的开发技术. 二.Ajax技术的核心 Aj ...

  2. Spring学习(23)--- AOP之Introductions应用

    简介允许一个切面声明一个实现指定接口的通知对象,并且提供了一个接口实现类来代表这些对象 由<aop:aspect>中的<aop:declare-parents>元素声明该元素用 ...

  3. ReactiveCocoa源码解析(二) Bag容器的代码实现

    今天博客我接着上篇博客的内容来,上篇博客我们详细的看了ReactiveSwift中的Observer已经Event的代码实现.接下来我们来看一下ReactiveSwift中的结构体Bag的实现.Bag ...

  4. Qt开发陷阱一QSTACKWIDGET

    原始日期:2015-10-14 00:55 1.使用QStackWidget控件的setCurrentIndex方法时,要注意参数0对应着ui上StackWidget的page1,而不是page0,没 ...

  5. Windows系统完全退出VMware方法

    原始日期:2013-11-30 16:09 事件起因:本来机子上装的Vbox,装了个winXp系统,目的是将一些开发用地软件工具神马的安装在虚拟机,保证主机的流畅稳定.无奈,Vbox对主机与虚拟机的文 ...

  6. 用JS来实现于截取中英文混合字符串方法(转载)

    网站制作过程中,提示层文字超出,需要JS做字符串截取,但是呢,我们常常会烦恼文字中英文混合如何判断,因为我们知道在JS中 string.length这个值是不考虑中英文的,但是计算机对中英文的识别是  ...

  7. WindowManager.LayoutParams的探究

    上次在子线程更新UI时用了一下WindowManager.LayoutParams,当时觉得不太顺手.以前都是用空参构造器,这次用了type和flag属性,出现了意想不到的效果.也看看源码吧,多锻炼锻 ...

  8. maven打包 bat自动化打包

    maven打包,首先cd到项目根目录,如果想跳过测试阶段,可用:mvn package -DskipTests bat命令,说明start是打开文件夹的意思:e: cd E:\workspace\it ...

  9. jquery移出select指定option

    $("#selectLine option[value!='']").remove();

  10. JAVA上传与下载

    java下载指定地址的文件 package com.test; import java.io.FileNotFoundException; import java.io.FileOutputStrea ...