单例模式

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. ci框架学习告一段落,总结一下

    从网上弄了一张框架学习思维导图,从图中就可以看出ci用了设计模式中的MVC架构,使得用起来很简单方便 用了大概两个星期开发了一个<文章管理系统>觉得开发过程中学到了很多,挺不错的,而且在学 ...

  2. 纯手工打造简单分布式爬虫(Python)

    前言 这次分享的文章是我<Python爬虫开发与项目实战>基础篇 第七章的内容,关于如何手工打造简单分布式爬虫 (如果大家对这本书感兴趣的话,可以看一下 试读样章),下面是文章的具体内容. ...

  3. # ? & 号在url中的的作用

    1. # 10年9月,twitter改版.一个显著变化,就是URL加入了"#!"符号.比如,改版前的用户主页网址为http://twitter.com/username改版后,就变 ...

  4. Git操作简介

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

  5. Spring事务管理注意小事项

    在service类前加上@Transactional,声明这个service所有方法需要事务管理.每一个业务方法开始时都会打开一个事务. Spring默认情况下会对运行期例外(RunTimeExcep ...

  6. 入门Android开发

    一个工作1年多一点的前端狗,由于公司需要,开始接触Android,也是第一次写博客,以后学到的技术每天都会写篇博客,让我们一起进步. Android 系统开发应用程序,为我们提供了哪些东西. 一.四大 ...

  7. 基于Json序列化和反序列化通用的封装

    1. 最近项目已经上线了 ,闲暇了几天 想将JSON的序列化以及反序列化进行重新的封装一下本人定义为JSONHelp,虽然Microsoft 已经做的很好了.但是我想封装一套为自己开发的项目使用.方便 ...

  8. spring的applicationContext.xml配置SessionFactory抛异常

    <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFa ...

  9. java 文件的编码 问题

    package com.io; public class Encodedemo { public static void main(String[] args)throws Exception{ // ...

  10. 关于WIN7 内存占用很大的 问题svchost.exe

    svchost.exe 是用来启动系统服务的,所以某个 svchost.exe 占用内存过大,可能就是它启动的那个服务占用内存过大,所以只要停止并禁用那个服务就行了. 一般来说占用内存最大的服务是 S ...