单例模式(单例设计模式)_第1页
单例模式(单例设计模式)_第2页
单例模式(单例设计模式)_第3页
单例模式(单例设计模式)_第4页
单例模式(单例设计模式)_第5页
已阅读5页,还剩6页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、单例模式(单例设计模式)在有些系统中,为了节省内存资源、保证数据内容的一致性,对某些类要求只能创建一个实例,这就是所谓的单例模式。单例模式的定义与特点单例(Singleton)模式的定义:指一个类只有一个实例,且该类能自行创建这个实例的一种模式。例如,Windows中只能打开管理器,这样可以避免因打开多个任务管理器窗口而造成内存资源的浪费,或出现各个窗口显示内容的不一致等错误。在计算机系统中,还有Windows的回收站、操作系统中的文件系统、多线程中的线程池、显卡的驱动程序对象、打印机的后台处理服务、应用程序的日志对象、数据库的连接池、网站的计数器、Web应用的配置对象、应用程序中的对话框、系

2、统中的缓存等常常被设计成单例。单例模式在现实生活中的应用也非常广泛,例如公司CEO、部门经理等都属于单例模型。J2EE标准中的Context和ServletContextConfig、框架应用中的ApplicationContext、数据库中的连接池等也都是单例模式。单例模式有3个特点:单例类只有一个实例对象;该单例对象必须由单例类自行创建;单例类对外提供一个访问该单例的全局访问点。单例模式的优点和缺点单例模式的优点:单例模式可以保证内存里只有一个实例,减少了内存的开销。可以避免对资源的多重占用。单例模式设置全局访问点,可以优化和共享资源的访问。单例模式的缺点:单例模式一般没有接口,扩展困难。

3、如果要扩展,则除了修改原来的代码,没有第二种途径,违背开闭原则。在并发测试中,单例模式不利于代码调试。在调试过程中,如果单例中的代码没有执行完,也不能模拟生成一个新的对象。单例模式的功能代码通常写在一个类中,如果功能设计不合理,则很容易违背单一职责原则。单例模式看起来非常简单,实现起来也非常简单。单例模式在面试中是一个高频面试题。希望大家能够认真学习,掌握单例模式,提升核心竞争力,给面试加分,顺利拿到Offer。单例模式的应用场景对于来说,单例模式可以保证在一个JVM中只存在单一实例。单例模式的应用场景主要有以下几个方面。需要频繁创建的一些类,使用单例可以降低系统的内存压力,减少GC。某类只要

4、求生成一个对象的时候,如一个班中的班长、每个人的身份证号等。某些类创建实例时占用资源较多,或实例化耗时较长,且经常使用。某类需要频繁实例化,而创建的对象又频繁被销毁的时候,如多线程的线程池、网络连接池等。频繁访问数据库或文件的对象。对于一些控制硬件级别的操作,或者从系统上来讲应当是单一控制逻辑的操作,如果有多个实例,则系统会完全乱套。当对象需要被共享的场合。由于单例模式只允许创建一个对象,共享该对象可以节省内存,并加快对象访问速度。如Web中的配置对象、数据库的连接池等。单例模式的结构与实现单例模式是设计模式中最简单的模式之一。通常,普通类的构造函数是公有的,外部类可以通过“new构造函数()

5、”来生成多个实例。但是,如果将类的构造函数设为私有的,外部类就无法调用该构造函数,也就无法生成多个实例。这时该类自身必须定义一个静态私有实例,并向外提供一个静态的公有函数用于创建或获取该静态私有实例。下面来分析其基本结构和实现方法。1.单例模式的结构单例模式的主要角色如下。单例类:包含一个实例且能自行创建这个实例的类。访问类:使用单例的类。其结构如图1所示。图1单例模式的结构图2.单例模式的实现Singleton模式通常有两种实现形式。第1种:懒汉式单例该模式的特点是类加载时没有生成单例,只有当第一次调用getlnstance方法时才去创建这个单例。代码如下保证在所有线程中同步避免类在外部被实

6、例化方法前加同步注意:如果编写的是多线程程序,则不要删除上例代码中的关键字volatile和synchronized,否则将存在线程非安全的问题。如果不删除这两个关键字就能保证线程安全,但是每次访问时都要同步,会影响性能,且消耗更多的资源,这是懒汉式单例的缺点。第2种:饿汉式单例该模式的特点是类一旦加载就创建一个单例,保证在调用getlnstanee方法之前单例已经存在了。publicclassHungrySingletonprivatestaticfinalHungrySingletoninstance=newHungrySingleton();privateHungrySingleton。

7、publicstaticHungrySingletongetInstance()returninstance;饿汉式单例在类创建的同时就已经创建好一个静态的对象供系统使用,以后不再改变,所以是线程安全的,可以直接用于多线程而不会出现问题。单例模式的应用实例【例1】用懒汉式单例模式模拟产生美国当今总统对象。分析:在每一届任期内,美国的总统只有一人,所以本实例适合用单例模式实现,图2所示是用懒汉式单例实现的结构图。publicstaticsynchmnizedPresidentgetlnstaneeLf(instaiice=null)PresidentQtelseSystem.qutpriniln

8、(有一个思统j不能产生新总统hrehirninstance;单例类I峽刃dem-insEiincs:President-PFtsrdent(+gednsiance():President4gelName():void谊问烫Sir)gleioiiLazy图2美国总统生成器的结构图程序代码如下:publicclassSingletonLazypublicstaticvoidmain(Stringargs)Presidentzt1=President.getInstance();zt1.getName();/输出总统的名字Presidentzt2=President.getInstance();zt

9、2.getName();输出总统的名字if(zt1=zt2)System.out.println(他们是同一人!);elseSystem.out.println(他们不是同一人!);classPresidentprivatestaticvolatilePresidentinstance=null;/保证instance在所有线程中同步/private避免类在外部被实例化privatePresident()System.out.println(产生一个总统!);publicstaticsynchronizedPresidentgetInstance()在getInstance方法上加同步if(i

10、nstance=null)instance=newPresident();elseSystem.out.println(已经有一个总统,不能产生新总统!);returninstance;publicvoidgetName()System.out.println(我是美国总统:特朗普);程序运行结果如下:产生一个总统!我是美国总统:特朗普。已经有一个总统,不能产生新总统!我是美国总统:特朗普。他们是同一人!【例2】用饿汉式单例模式模拟产生猪八戒对象。分析:同上例类似,猪八戒也只有一个,所以本实例同样适合用单例模式实现本实例由于要显示猪八戒的图像,所以用到了框架窗体JFrame组件,这里的猪八戒类

11、是单例类,可以将其定义成面板JPanel的子类,里面包含了标签,用于保存猪八戒的图像,客户窗体可以获得猪八戒对象,并显示它图3所示是用饿汉式单例实现的结构图。图3猪八戒生成器的结构图程序代码如下:importjava.awt.*;importjavax.swing.*;publicclassSingletonEagerpublicstaticvoidmain(Stringargs)JFramejf=newJFrame(”饿汉单例模式测试);jf.setLayout(newGridLayout(1,2);ContainercontentPane=jf.getContentPane();Bajie

12、obj1=Bajie.getInstance();contentPane.add(obj1);Bajieobj2=Bajie.getInstance();contentPane.add(obj2);if(obj1=obj2)System.out.println(哋们是同一人!);elseSystem.out.println(哋们不是同一人!);jf.pack();jf.setVisible(true);jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);classBajieextendsJPanelprivatestaticBajieinstan

13、ce=newBajie();privateBajie()JLabell1=newJLabel(newImageIcon(src/Bajie.jpg);this.add(l1);publicstaticBajiegetInstance()returninstance;程序运行结果如图4所示。图4猪八戒生成器的运行结果单例模式的扩展单例模式可扩展为有限的多例(Multitcm)模式,这种模式可生成有限个实例并保存在ArayList中,客户需要时可随机获取,如图5所示。staticforlistadd(rwwMultiton(i)pubEicstaticMullitorigctKardomInsta

14、nce仃intviluc-(int)(MtlirardomO*nhreturn(value);缶例类Multfroniisx:ArrayLifit访问类Client#instance:MWIicons-Multitnn(nzint)+gdRiiJidomlnslante0:Mulliltm图5有限的多例模式的结构图单例模式在D源码中的应用DK中Runtime类使用了单例模式,源码如下。priingnirrnninngnipiingnignirrnrrnniprini单例模式在Sprin源码中的应用下面介绍单例模式在Spring中的应用。在Spring中,bean可以被定义为两种模式:proto

15、type(多例)和singleton(单例)。singleton(单例):只有一个共享的实例存在,所有对这个bean的请求都会返回唯一的实例。bean实例,类似于new。prototype(多例):对这个bean的每次请求都会创建一个新的实例配置文件内容如下:nini测试内容如下:ingniprpipipiiiinSringrgppiinnnnngngpngpngS单例:prinnS多例:Pinnppingnnpprpnppiinnppningnningnnprpnprp运行结果如下:单例:r多例:Springbean默认是单例模式。Spring中加载单例的过程都是在BeanFactory的g

16、etBean()方法中被定义的,其默认的功能在AbstractBeanFactory类中实现,主要包含两个功能。从缓存中获取单例Bean。Bean的实例中获取对象。getBean()方法最终会调用AbstractBeanFactory的doGetBean()方法,源码如下。protectedTdoGetBean(finalStringname,NullablefinalClassrequiredType,NullablefinalObjectargs,booleantypeCheckOnly)throwsBeansException对传入的beanName稍作修改,防止有一些非法字段,然后提取

17、Bean的NamefinalStringbeanName=transformedBeanName(name);Objectbean;直接从缓存中获取单例工厂中的objectFactory单例ObjectsharedInstance=getsingleton(beanName);if(sharedInstance!=null&args=null)if(logger.isDebugEnabled()if(isSingletonCurrentlylnCreation(beanName)logger.debug(Returningeagerlycachedinstanceofsingletonbean

18、+beanName+thatisnotfullyinitializedyet-aconsequenceofacircularreference);else返回对应的实例,从Bean实例中获取对象bean=getObjectForBeanInstance(sharedInstance,name,beanName,null);elsegetBean()方法不仅处理单例对象的逻辑,还处理原型对象的逻辑。继续看getSingleton()方法的代码实现。getSingleton()的工作流程:singletonObjects-earlySingletonObjects-singletonFactori

19、es-创建单例实例/*单例对象的缓存*/privatefinalMapvString,ObjectsingletonObjects=newConcurrentHashMap(256);protectedObjectgetSingleton(StringbeanName,booleanallowEarlyReference)首先通过名字查找这个Bean是否存在ObjectsingletonObject=this.singletonObjects.get(beanName);if(singletonObject=null&isSingletonCurrentlylnCreation(beanNam

20、e)synchronized(this.singletonObjects)查看缓存中是否存在这个BeansingletonObject=this.earlySingletonObjects.get(beanName);如果这个时候的Bean实例还为空并且允许懒加载if(singletonObjects=null&allowEarlyReference)ObjectFactorysingletonFactory=this.singletonFactories.get(beanName);if(singletonFactory!=null)singletonObject=singletonFact

21、ory.getObject();this.earlySingletonObjects.put(beanName,singletonObject);this.singletonFactories.remove(beanName);returnsingletonObject;在上面代码片段中,synchronized(this.singletonObjects)是关键,但是前提条件isSingletonCurrentlylnCreation的返回值也是true,也就是这个Bean正在被创建。因此,第一次调用doGetBean()的时候,getSingleton()基本上都是返回null,所以会继续

22、执行doGetBean()方法中后面的逻辑。protectedTdoGetBean(finalStringname,NullablefinalClassrequiredType,NullablefinalObjectargs,booleantypeCheckOnly)throwsBeansException/获取beanDefinitionfinalRootBeanDefinitionmbd=getMergedLocalBeanDefinition(beanName);checkMergedBeanDefinition(mbd,beanName,args);/Guaranteeinitiali

23、zationofbeansthatthecurrentbeandependson.StringdependsOn=mbd.getDependsOn();if(dependsOn!=null)for(Stringdep:dependsOn)if(isDependent(beanName,dep)thrownewBeanCreationException(mbd.getResourceDescription(),beanName,Circulardepends-onrelationshipbetween+beanName+and+dep+);registerDependentBean(dep,be

24、anName);trygetBean(dep);catch(NoSuchBeanDefinitionExceptionex)thrownewBeanCreationException(mbd.getResourceDescription(),beanName,+beanName+dependsonmissingbean+dep+,ex);/Createbeaninstance.if(mbd.isSingleton()sharedInstance=getSingleton(beanName,()-tryreturncreateBean(beanName,mbd,args);catch(Beans

25、Exceptionex)/Explicitlyremoveinstancefromsingletoncache:Itmighthavebeenputthere/eagerlybythecreationprocess,toallowforcircularreferenceresolution./Alsoremoveanybeansthatreceivedatemporaryreferencetothebean.destroySingleton(beanName);throwex;);bean=getObjectForBeanInstance(sharedInstance,name,beanNam

26、e,mbd);可以看到,在BeanFactory中,从XML中解析出来的相关配置信息被放在BeanDefinitionMap中,通过这个Map获取RootBeanDefinition,然后执行判断语句if(mbd.isSingleton()o如果是单例的,则接着调用getSingleton()的重载方法,传入mbd参数。当从缓存中加载单例对象时,会把当前的单例对象在singletonObjects中存放一份,这样可以保证在调用getBean()方法的时候,singletonObjects中永远只有一个实例,在获取对象时才会给它分配内存,既保证了内存高效利用,又是线程安全的。publicObje

27、ctgetSingleton(StringbeanName,ObjectFactorysingletonFactory)Assert.notNull(beanName,Beannamemustnotbenull);synchronized(this.singletonObjects)/直接从缓存中获取单例BeanObjectsingletonObject=this.singletonObjects.get(beanName);if(singletonObject=null)if(this.singletonsCurrentlylnDestruction)thrownewBeanCreationNotAllowedException(beanName,Singletonbeancreationnotallowedwhilesingletonsofthisfactoryareindestruction+(DonotrequestabeanfromaBeanFactoryinadestroymethodimplementation!);if(logger.isDebugEnabled()logger.debug(Creatingsharedinstanceofsingletonbean+beanName+);beforeSingletonCreation(bea

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论