单例模式

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. charles连接手机抓包

    写给我自己: 如果是使用charles抓包.一定要tm的保证手机和电脑连的是一个网. 1.proxy setting,查看charles,端口 2.勾选 3.ipconfig,查看自己电脑的ip地址 ...

  2. 可视化之Earth NullSchool

    上两篇我们分别介绍了<Berkeley Earth>和<AQICN>两个网站,今天来看一下Earth NullSchool. 这个网站的特色是风向图,之前有一篇可视化之风向图, ...

  3. 判断客户端使用的是安卓还是苹果,然后加载对应的css文件

    <script type="text/javascript" charset="utf-8"> var browser = { versions: ...

  4. python 数据类型 -- set

    0. set : 无序的,不重复的序列. 1. 创建 set s = set() s = set(list) # list 为可迭代对象的即可 s = {1,23,4} 2. 内建方法 1) 一般方法 ...

  5. c++课程设计之菜单选择

    a) 从键盘输入n个数,选择升序还是降序输出 b)创新了日历 c) 添加了射箭游戏 d)还加入了好玩的24点游戏     学生签名:  年  月   日   课程设计(论文)评阅意见 等 级 项    ...

  6. nginx是什么nginx安装与配置之windows版

    1.nginx是什么 为了快速了解nginx我们先引用网上的nginx介绍: Nginx ("engine x") 是一个高性能的HTTP和反向代理服务器,也是一个IMAP/POP ...

  7. 【Android Developers Training】 19. 序言:通过Fragments构建动态UI

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  8. 使用Scribefire在博客中插入语法高亮 II

    效果如下, 这是我们在Scribefire中添加的code按钮,单击此按钮,则会出现 在codeHere中直接输入代码就可以了. 查看html 可以看到,其中已经添加了<pre>标签. 下 ...

  9. 学习java 的经验

    一.学习java首先应该对他有个全局的看法 ,他由几部分组成 1.java 的基础语法 2.使用Swing 来做桌面应用,可做嵌入式开发. 3.JDBC数据库的链接 4.网络编程,主要是socket编 ...

  10. 代码规范--捡拾(SQL语句)

    最近在看阿里的JAVA开发手册,话不多说进入正题. 1.[强制]不使用count(列名)或者是count(常量)代替count(*) 因为count(*)会统计NULL值,前面的两个不会 2.[强制] ...