收藏 分销(赏)

单例模式.pptx

上传人:人****来 文档编号:4408402 上传时间:2024-09-19 格式:PPTX 页数:44 大小:221.04KB
下载 相关 举报
单例模式.pptx_第1页
第1页 / 共44页
单例模式.pptx_第2页
第2页 / 共44页
单例模式.pptx_第3页
第3页 / 共44页
单例模式.pptx_第4页
第4页 / 共44页
单例模式.pptx_第5页
第5页 / 共44页
点击查看更多>>
资源描述

1、1.1.场场 景景 问问 题题 1.1 1.1读取配置文件的内容读取配置文件的内容考虑这样一个应用,读取配置文件的内容。考虑这样一个应用,读取配置文件的内容。很多应用项目,都有与应用相关的配置文件,这很多应用项目,都有与应用相关的配置文件,这些配置文件很多是由项目开发人员自定义的,在些配置文件很多是由项目开发人员自定义的,在里面定义一些应用需要的参数数据。当然在实际里面定义一些应用需要的参数数据。当然在实际的项目中,这种配置文件多采用的项目中,这种配置文件多采用xmlxml格式,也有采格式,也有采用用propertiesproperties格式的,毕竟使用格式的,毕竟使用JavaJava来读取

2、来读取propertiesproperties格式的配置文件比较简单。格式的配置文件比较简单。现在要读取配置文件的内容,该如何实现呢?现在要读取配置文件的内容,该如何实现呢?1.21.2不用模式的解决方案不用模式的解决方案有些朋友会想,要读取配置文件的内容,有些朋友会想,要读取配置文件的内容,这也不是个困难的事情,直接读取文件的这也不是个困难的事情,直接读取文件的内容,然后把文件内容存放在相应的数据内容,然后把文件内容存放在相应的数据对象里面就可以了。真的这么简单吗?先对象里面就可以了。真的这么简单吗?先实现看看吧。实现看看吧。为了示例简单,假设系统采用的是为了示例简单,假设系统采用的是pro

3、pertiesproperties格式的配置文件。格式的配置文件。(1 1)直接使用)直接使用JavaJava来读取配置文件的示例来读取配置文件的示例代码如下:代码如下:/读取应用配置文件读取应用配置文件publicclassAppConfigprivateStringparameterA;/用来存放配置文件中参数用来存放配置文件中参数A的值的值privateStringparameterB;/用来存放配置文件中参数用来存放配置文件中参数B的值的值publicStringgetParameterA()/注意:只有访问参数的方法,注意:只有访问参数的方法,没有设置参数的方法没有设置参数的方法re

4、turnparameterA;publicStringgetParameterB()returnparameterB;/构造方法构造方法publicAppConfig()/调用读取配置文件的方法调用读取配置文件的方法readConfig();privatevoidreadConfig()/读取配置文件,把配置文件中的内容读出来设读取配置文件,把配置文件中的内容读出来设置到属性上置到属性上Propertiesp=newProperties();InputStreamin=null;tryin=AppConfig.class.getResourceAsStream(AppConfig.proper

5、ties);p.load(in);/把配置文件中的内容读出来设置到属性上把配置文件中的内容读出来设置到属性上this.parameterA=p.getProperty(paramA);this.parameterB=p.getProperty(paramB);catch(IOExceptione)System.out.println(装载配置文件出错了,具体堆栈信息如下:装载配置文件出错了,具体堆栈信息如下:);e.printStackTrace();finallytryin.close();catch(IOExceptione)e.printStackTrace();(2 2)应用的配置文件

6、,名字是)应用的配置文件,名字是AppConfig.propertiesAppConfig.properties,放在放在AppConfigAppConfig相同的包里面。简单示例如下:相同的包里面。简单示例如下:paramA=a paramB=bparamA=a paramB=b(3 3)写个客户端来测试一下。示例代码如下:)写个客户端来测试一下。示例代码如下:public class Client public class Client public static void main(String args)public static void main(String args)/创建读取

7、应用配置的对象创建读取应用配置的对象 AppConfig config=new AppConfig();AppConfig config=new AppConfig();String paramA=config.getParameterA();String paramA=config.getParameterA();String paramB=config.getParameterB();String paramB=config.getParameterB();System.out.println System.out.println (paramA=+paramA+,paramB=+para

8、mB);(paramA=+paramA+,paramB=+paramB);运行结果如下:运行结果如下:paramA=a,paramB=b1.3有何问题 上面的实现很简单,很容易的就实现要求的功能。上面的实现很简单,很容易的就实现要求的功能。仔细想想,有没有什么问题呢?仔细想想,有没有什么问题呢?看看客户端使用这个类的地方,是通过看看客户端使用这个类的地方,是通过newnew一个一个AppConfigAppConfig的实例来得到一个操作配置文件内容的的实例来得到一个操作配置文件内容的对象。如果在系统运行中,有很多地方都需要使对象。如果在系统运行中,有很多地方都需要使用配置文件的内容,也就是说很

9、多地方都需要创用配置文件的内容,也就是说很多地方都需要创建建AppConfigAppConfig对象的实例。对象的实例。换句话说,在系统运行期间,系统中会存在很多换句话说,在系统运行期间,系统中会存在很多个个AppConfigAppConfig的实例对象,这有什么问题吗?的实例对象,这有什么问题吗?当然有问题了,试想一下,每一个当然有问题了,试想一下,每一个AppConfigAppConfig实例对象里面都封装着配置文件实例对象里面都封装着配置文件的内容,系统中有多个的内容,系统中有多个AppConfigAppConfig实例对象,实例对象,也就是说系统中会同时存在多份配置文件也就是说系统中会

10、同时存在多份配置文件的内容,这样会严重浪费内存资源。如果的内容,这样会严重浪费内存资源。如果配置文件内容较少,问题还小一点,如果配置文件内容较少,问题还小一点,如果配置文件内容本来就多的话,对于系统资配置文件内容本来就多的话,对于系统资源的浪费问题就大了。事实上,对于源的浪费问题就大了。事实上,对于AppConfigAppConfig这种类,在运行期间,只需要一这种类,在运行期间,只需要一个实例对象就是够了。个实例对象就是够了。把上面的描述进一步抽象一下,问把上面的描述进一步抽象一下,问题就出来了:在一个系统运行期间,某个题就出来了:在一个系统运行期间,某个类只需要一个类实例就可以了,那么应该

11、类只需要一个类实例就可以了,那么应该怎样实现呢?怎样实现呢?2 2 解决方案解决方案 2.1 2.1 单例模式来解决单例模式来解决用来解决上述问题的一个合理的解决方案就是单例模式。用来解决上述问题的一个合理的解决方案就是单例模式。那么什么是单例模式呢?那么什么是单例模式呢?(1 1)单例模式定义)单例模式定义保证一个类仅有一个实例,并提供一个访问它的全局访问保证一个类仅有一个实例,并提供一个访问它的全局访问点。点。(2 2)应用单例模式来解决的思路)应用单例模式来解决的思路仔细分析上面的问题,现在一个类能够被创建多个实例,仔细分析上面的问题,现在一个类能够被创建多个实例,问题的根源在于类的构造

12、方法是公开的,也就是可以让类问题的根源在于类的构造方法是公开的,也就是可以让类的外部来通过构造方法创建多个实例。换句话说,只要类的外部来通过构造方法创建多个实例。换句话说,只要类的构造方法能让类的外部访问,就没有办法去控制外部来的构造方法能让类的外部访问,就没有办法去控制外部来创建这个类的实例个数。创建这个类的实例个数。要想控制一个类只被创建一个实例,那么首要的问题就是要想控制一个类只被创建一个实例,那么首要的问题就是要把创建实例的权限收回来,让类自身来负责自己类实例要把创建实例的权限收回来,让类自身来负责自己类实例的创建工作,然后由这个类来提供外部可以访问这个类实的创建工作,然后由这个类来提

13、供外部可以访问这个类实例的方法,这就是单例模式的实现方式例的方法,这就是单例模式的实现方式。2.2 2.2 模式结构和说明模式结构和说明单例模式结构图:单例模式结构图:SingletonSingleton:负责创建负责创建SingletonSingleton类自己的唯一实例,类自己的唯一实例,并提供一个并提供一个getInstancegetInstance的方法,的方法,让外部来访问这个让外部来访问这个类的唯一实例。类的唯一实例。2.3 2.3 单例模式示例代码单例模式示例代码在在JavaJava中,单例模式的实现又分为两种,中,单例模式的实现又分为两种,一种称为懒汉式,一种称为饿汉式,其实一

14、种称为懒汉式,一种称为饿汉式,其实就是在具体创建对象实例的处理上,有不就是在具体创建对象实例的处理上,有不同的实现方式。下面分别来看这两种实现同的实现方式。下面分别来看这两种实现方式的代码示例。为何这么写,具体的在方式的代码示例。为何这么写,具体的在后面再讲述。后面再讲述。懒汉懒汉 饿汉饿汉2.4 使用单例模式重写示例 要使用单例模式来重写示例,由于单例模要使用单例模式来重写示例,由于单例模式有两种实现方式,这里选一种来实现就式有两种实现方式,这里选一种来实现就好了,就选择饿汉式的实现方式来重写示好了,就选择饿汉式的实现方式来重写示例吧。例吧。采用饿汉式的实现方式来重写实例的示例采用饿汉式的实

15、现方式来重写实例的示例代码如下:代码如下:单例模式实例 关于饿汉式、懒汉式的名称说明:饿汉式、懒汉式其实是一种比较形象的称谓。饿汉式、懒汉式其实是一种比较形象的称谓。所谓饿汉式,既然饿,那么在创建对象实例的时所谓饿汉式,既然饿,那么在创建对象实例的时候就比较着急,饿了嘛,于是就在装载类的时候就创建对候就比较着急,饿了嘛,于是就在装载类的时候就创建对象实例,写法如下:象实例,写法如下:private static Singleton uniqueInstance=new Singleton();所谓懒汉式,既然是懒,那么在创建对象实例所谓懒汉式,既然是懒,那么在创建对象实例的时候就不着急,会一直

16、等到马上要使用对象实例的时候的时候就不着急,会一直等到马上要使用对象实例的时候才会创建,懒人嘛,总是推托不开的时候才去真正执行工才会创建,懒人嘛,总是推托不开的时候才去真正执行工作,因此在装载对象的时候不创建对象实例,写法如下:作,因此在装载对象的时候不创建对象实例,写法如下:private static Singleton uniqueInstance=null;而是等到第一次使用的时候,才去创建实例,也就是在而是等到第一次使用的时候,才去创建实例,也就是在getInstance方法里面去判断和创建方法里面去判断和创建3 3 模式讲解模式讲解 3.1 3.1 认识单例模式认识单例模式(1 1

17、)单例模式的功能)单例模式的功能单例模式的功能是用来保证这个类在运行期间只单例模式的功能是用来保证这个类在运行期间只会被创建一个类实例,另外单例模式还提供了一会被创建一个类实例,另外单例模式还提供了一个全局唯一访问这个类实例的访问点,就是那个个全局唯一访问这个类实例的访问点,就是那个getInstancegetInstance的方法。不管采用懒汉式还是饿汉式的方法。不管采用懒汉式还是饿汉式的实现方式,这个全局访问点是一样的。的实现方式,这个全局访问点是一样的。对于单例模式而言,不管采用何种实现方式,它对于单例模式而言,不管采用何种实现方式,它都是只关心类实例的创建问题,并不关心具体的都是只关心

18、类实例的创建问题,并不关心具体的业务功能。业务功能。(2 2)单例模式的范围)单例模式的范围也就是在多大范围内是单例呢?也就是在多大范围内是单例呢?观察上面的实现可以知道,目前观察上面的实现可以知道,目前JavaJava里面实现的里面实现的单例是一个虚拟机的范围。因为装载类的功能是单例是一个虚拟机的范围。因为装载类的功能是虚拟机的,所以一个虚拟机在通过自己的虚拟机的,所以一个虚拟机在通过自己的ClassLoaderClassLoader装载饿汉式实现的单例类的时候就会装载饿汉式实现的单例类的时候就会创建一个类的实例。创建一个类的实例。这就意味着如果一个机器上有多个虚拟机,那么这就意味着如果一个

19、机器上有多个虚拟机,那么每个虚拟机里面都应该有一个这个类的实例,但每个虚拟机里面都应该有一个这个类的实例,但是整个机器上就有很多个实例了。是整个机器上就有很多个实例了。另外请注意一点,这里讨论的单例模式并不适用另外请注意一点,这里讨论的单例模式并不适用于集群环境,对于集群环境下的单例这里不去讨于集群环境,对于集群环境下的单例这里不去讨论,那不属于这里的内容范围。论,那不属于这里的内容范围。(3 3)单例模式的命名)单例模式的命名一般建议单例模式的方法命名为:一般建议单例模式的方法命名为:getInstancegetInstance()(),这个方法的返回类型肯定是单例类的,这个方法的返回类型肯

20、定是单例类的类型了。类型了。getInstancegetInstance方法可以有参数,这方法可以有参数,这些参数可能是创建类实例所需要的参数,些参数可能是创建类实例所需要的参数,当然,大多数情况下是不需要的。当然,大多数情况下是不需要的。单例模式的名称:单例、单件、单体等等,单例模式的名称:单例、单件、单体等等,翻译的不同,都是指的同一个模式。翻译的不同,都是指的同一个模式。3.2 3.2 懒汉式和饿汉式实现懒汉式和饿汉式实现前面提到了单例模式有两种典型的解决方前面提到了单例模式有两种典型的解决方案,一种叫懒汉式,一种叫饿汉式,这两案,一种叫懒汉式,一种叫饿汉式,这两种方式究竟是如何实现的,

21、下面分别来看种方式究竟是如何实现的,下面分别来看看。为了看得更清晰一点,只是实现基本看。为了看得更清晰一点,只是实现基本的单例控制部分,不再提供示例的属性和的单例控制部分,不再提供示例的属性和方法了方法了 第一种方案第一种方案 懒汉式懒汉式 1 1)私有化构造方法)私有化构造方法要想在运行期间控制某一个类的实例只有一个,要想在运行期间控制某一个类的实例只有一个,首要的任务就是要控制创建实例的地方,也就是首要的任务就是要控制创建实例的地方,也就是不能随随便便就可以创建类实例,否则就无法控不能随随便便就可以创建类实例,否则就无法控制所创建的实例个数了。现在是让使用类的地方制所创建的实例个数了。现在

22、是让使用类的地方来创建类实例,也就是在类外部来创建类实例。来创建类实例,也就是在类外部来创建类实例。那么怎样才能让类的外部不能创建一个类的实例那么怎样才能让类的外部不能创建一个类的实例呢?很简单,私有化构造方法就可以了。示例代呢?很简单,私有化构造方法就可以了。示例代码如下:码如下:private Singleton()private Singleton()2 2)提供获取实例的方法)提供获取实例的方法构造方法被私有化了,外部使用这个类的构造方法被私有化了,外部使用这个类的地方不干了,外部创建不了类实例就没有地方不干了,外部创建不了类实例就没有办法调用这个对象的方法,就实现不了功办法调用这个对

23、象的方法,就实现不了功能调用。这可不行,经过思考,单例模式能调用。这可不行,经过思考,单例模式决定让这个类提供一个方法来返回类的实决定让这个类提供一个方法来返回类的实例,方便外面使用。示例代码如下:例,方便外面使用。示例代码如下:public Singleton getInstance()public Singleton getInstance()3 3)把获取实例的方法变成静态的)把获取实例的方法变成静态的又有新的问题了,获取对象实例的这个方法是一又有新的问题了,获取对象实例的这个方法是一个实例方法,也就是说客户端要想调用这个方法,个实例方法,也就是说客户端要想调用这个方法,需要先得到类实例

24、,然后才可以调用,可是这个需要先得到类实例,然后才可以调用,可是这个方法就是为了得到类实例,这样一来不就形成一方法就是为了得到类实例,这样一来不就形成一个死循环了吗?这也是典型的个死循环了吗?这也是典型的“先有鸡还是先有先有鸡还是先有蛋的问题蛋的问题”。解决方法也很简单,在方法上加上解决方法也很简单,在方法上加上staticstatic,这样,这样就可以直接通过类来调用这个方法,而不需要先就可以直接通过类来调用这个方法,而不需要先得到类实例。示例代码如下:得到类实例。示例代码如下:public static Singleton getInstance()public static Single

25、ton getInstance()4 4)定义存储实例的属性)定义存储实例的属性方法定义好了,那么方法内部如何实现呢方法定义好了,那么方法内部如何实现呢?如果直接创建实例并返回,这样行不行?如果直接创建实例并返回,这样行不行呢?示例代码如下:呢?示例代码如下:public static Singleton getInstance()public static Singleton getInstance()return new Singleton();return new Singleton();当然不行了,如果每次客户端访问都这样当然不行了,如果每次客户端访问都这样直接直接newnew一个实例

26、,那肯定会有多个实例,一个实例,那肯定会有多个实例,根本实现不了单例的功能。根本实现不了单例的功能。怎么办呢?单例模式想到了一个办法,那怎么办呢?单例模式想到了一个办法,那就是用一个属性来记录自己创建好的类实就是用一个属性来记录自己创建好的类实例。当第一次创建后,就把这个实例保存例。当第一次创建后,就把这个实例保存下来,以后就可以复用这个实例,而不是下来,以后就可以复用这个实例,而不是重复创建对象实例了。示例代码如下:重复创建对象实例了。示例代码如下:private Singleton instance=null;private Singleton instance=null;5 5)把这个属

27、性也定义成静态的)把这个属性也定义成静态的这个属性变量应该在什么地方用呢?肯定这个属性变量应该在什么地方用呢?肯定是第一次创建类实例的地方,也就是在前是第一次创建类实例的地方,也就是在前面那个返回对象实例的静态方法里面使用。面那个返回对象实例的静态方法里面使用。由于要在一个静态方法里面使用,所以这由于要在一个静态方法里面使用,所以这个属性被迫成为一个类变量,要强制加上个属性被迫成为一个类变量,要强制加上staticstatic,也就是说,这里并没有使用,也就是说,这里并没有使用staticstatic的特性。示例代码如下:的特性。示例代码如下:private static Singleton

28、instance=private static Singleton instance=null;null;6 6)实现控制实例的创建)实现控制实例的创建现在应该到现在应该到getInstancegetInstance方法里面实现控制方法里面实现控制实例的创建了。控制的方式很简单,只要实例的创建了。控制的方式很简单,只要先判断一下是否已经创建过实例就可以了。先判断一下是否已经创建过实例就可以了。如何判断?那就看存放实例的属性是否有如何判断?那就看存放实例的属性是否有值,如果有值,说明已经创建过了,如果值,如果有值,说明已经创建过了,如果没有值,则应该创建一个。示例代码如下:没有值,则应该创建一个

29、。示例代码如下:publicstaticSingletongetInstance()/先判断先判断instance是否有值是否有值if(instance=null)/如果没有值,说明还没有创建过实例,那如果没有值,说明还没有创建过实例,那就创建一个就创建一个/并把这个实例设置给并把这个实例设置给instanceinstance=newSingleton();/如果有值,或者是创建了值,那就直接使用如果有值,或者是创建了值,那就直接使用returninstance;7 7)完整的实现)完整的实现至此,成功解决了在运行期间,控制某个至此,成功解决了在运行期间,控制某个类只被创建一个实例的要求。完整

30、的代码类只被创建一个实例的要求。完整的代码如下。为了大家好理解,用注释标示了代如下。为了大家好理解,用注释标示了代码的先后顺序。码的先后顺序。publicclassSingleton/4:定义一个变量来存储创建好的类实例:定义一个变量来存储创建好的类实例/5:因为这个变量要在静态方法中使用,所以需要加上:因为这个变量要在静态方法中使用,所以需要加上static修饰修饰privatestaticSingletoninstance=null;/1:私有化构造方法,便于在内部控制创建实例的数目:私有化构造方法,便于在内部控制创建实例的数目privateSingleton()/2:定义一个方法来为客户

31、端提供类实例:定义一个方法来为客户端提供类实例/3:这个方法需要定义成类方法,也就是要加:这个方法需要定义成类方法,也就是要加staticpublicstaticSingletongetInstance()/6:判断存储实例的变量是否有值:判断存储实例的变量是否有值if(instance=null)/6.1:如果没有,就创建一个类实例,并把值赋给存储类实:如果没有,就创建一个类实例,并把值赋给存储类实例的变量例的变量instance=newSingleton();/6.2:如果有值,那就直接使用:如果有值,那就直接使用returninstance;第二种方案第二种方案 饿汉式饿汉式 这种方案跟

32、第一种方案相比,前面的私有这种方案跟第一种方案相比,前面的私有化构造方法,提供静态的化构造方法,提供静态的getInstancegetInstance方法方法来返回实例等步骤都一样。来返回实例等步骤都一样。差别在如何实差别在如何实现现getInstancegetInstance方法方法,在这个地方,单例模,在这个地方,单例模式还想到了另外一种方法来实现式还想到了另外一种方法来实现getInstancegetInstance方法。方法。不就是要控制只创造一个实例吗?那么有不就是要控制只创造一个实例吗?那么有没有什么现成的解决办法呢?很快,单例没有什么现成的解决办法呢?很快,单例模式回忆起了模式回

33、忆起了JavaJava中中staticstatic的特性:的特性:staticstatic变量在类装载的时候进行初始化变量在类装载的时候进行初始化 多个实例的多个实例的staticstatic变量会共享同一块内存变量会共享同一块内存区域。区域。这就意味着,在这就意味着,在JavaJava中,中,staticstatic变量只会变量只会被初始化一次,就是在类装载的时候,而被初始化一次,就是在类装载的时候,而且多个实例都会共享这个内存空间,这不且多个实例都会共享这个内存空间,这不就是单例模式要实现的功能吗?真是得来就是单例模式要实现的功能吗?真是得来全不费功夫啊。根据这些知识,写出了第全不费功夫啊

34、。根据这些知识,写出了第二种解决方案的代码,示例代码如下:二种解决方案的代码,示例代码如下:publicclassSingleton/4:定义一个静态变量来存储创建好的类实例:定义一个静态变量来存储创建好的类实例/直接在这里创建类实例,只会创建一次直接在这里创建类实例,只会创建一次privatestaticSingletoninstance=newSingleton();/1:私有化构造方法,便于在内部控制创建实例的数目:私有化构造方法,便于在内部控制创建实例的数目privateSingleton()/2:定义一个方法来为客户端提供类实例:定义一个方法来为客户端提供类实例/3:这个方法需要定义

35、成类方法,也就是要加:这个方法需要定义成类方法,也就是要加static/这个方法里面就不需要控制代码了这个方法里面就不需要控制代码了publicstaticSingletongetInstance()/5:直接使用已经创建好的实例:直接使用已经创建好的实例returninstance;注意一下,这个方案是用到了注意一下,这个方案是用到了staticstatic的特性的,的特性的,而第一个方案是没有用到的,因此两个方案的步而第一个方案是没有用到的,因此两个方案的步骤会有一些不同,在第一个方案里面,强制加上骤会有一些不同,在第一个方案里面,强制加上staticstatic也是算作一步的,而在这个方

36、案里面,是也是算作一步的,而在这个方案里面,是主动加上主动加上staticstatic,就不单独算作一步了。,就不单独算作一步了。所以在查看上面两种方案的代码的时候,仔细看所以在查看上面两种方案的代码的时候,仔细看看编号,顺着编号的顺序看,可以体会出两种方看编号,顺着编号的顺序看,可以体会出两种方案的不一样来。案的不一样来。不管是采用哪一种方式,在运行期间,都只会生不管是采用哪一种方式,在运行期间,都只会生成一个实例,而访问这些类的一个全局访问点,成一个实例,而访问这些类的一个全局访问点,就是那个静态的就是那个静态的getInstancegetInstance方法。方法。单例模式的调用顺序示意

37、图单例模式的调用顺序示意图 (懒汉)(懒汉)单例模式的调用顺序示意图单例模式的调用顺序示意图 (饿汉)(饿汉)3.3 3.3 延迟加载的思想延迟加载的思想 单例模式的懒汉式实现方式体现了延迟加单例模式的懒汉式实现方式体现了延迟加载的思想,什么是延迟加载呢?载的思想,什么是延迟加载呢?通俗点说,就是一开始不要加载资源或者通俗点说,就是一开始不要加载资源或者数据,一直等,等到马上就要使用这个资数据,一直等,等到马上就要使用这个资源或者数据了,躲不过去了才加载,所以源或者数据了,躲不过去了才加载,所以也称也称Lazy LoadLazy Load,不是懒惰啊,是,不是懒惰啊,是“延迟加延迟加载载”,这

38、在实际开发中是一种很常见的思,这在实际开发中是一种很常见的思想,尽可能的节约资源。想,尽可能的节约资源。体现在什么地方呢?看如下代码体现在什么地方呢?看如下代码3.4 3.4 缓存的思想缓存的思想单例模式的懒汉式实现还体现了缓存的思想,缓单例模式的懒汉式实现还体现了缓存的思想,缓存也是实际开发中非常常见的功能。存也是实际开发中非常常见的功能。简单讲就是,如果某些资源或者数据会被频繁的简单讲就是,如果某些资源或者数据会被频繁的使用,而这些资源或数据存储在系统外部,比如使用,而这些资源或数据存储在系统外部,比如数据库、硬盘文件等,那么每次操作这些数据的数据库、硬盘文件等,那么每次操作这些数据的时候

39、都从数据库或者硬盘上去获取,速度会很慢,时候都从数据库或者硬盘上去获取,速度会很慢,会造成性能问题。会造成性能问题。一个简单的解决方法就是:把这些数据缓存到内一个简单的解决方法就是:把这些数据缓存到内存里面,每次操作的时候,先到内存里面找,看存里面,每次操作的时候,先到内存里面找,看有没有这些数据,如果有,那么就直接使用,如有没有这些数据,如果有,那么就直接使用,如果没有那么就获取它,并设置到缓存中,下一次果没有那么就获取它,并设置到缓存中,下一次访问的时候就可以直接从内存中获取了。从而节访问的时候就可以直接从内存中获取了。从而节省大量的时间,当然,缓存是一种典型的空间换省大量的时间,当然,缓

40、存是一种典型的空间换时间的方案。时间的方案。缓存在单例模式的实现中怎么体现的呢?缓存在单例模式的实现中怎么体现的呢?1 1、时间和空间、时间和空间比较上面两种写法:懒汉式是典型的时间换空间,比较上面两种写法:懒汉式是典型的时间换空间,也就是每次获取实例都会进行判断,看是否需要也就是每次获取实例都会进行判断,看是否需要创建实例,浪费判断的时间。当然,如果一直没创建实例,浪费判断的时间。当然,如果一直没有人使用的话,那就不会创建实例,则节约内存有人使用的话,那就不会创建实例,则节约内存空间。空间。饿汉式是典型的空间换时间,当类装载的时候就饿汉式是典型的空间换时间,当类装载的时候就会创建类实例,不管

41、你用不用,先创建出来,然会创建类实例,不管你用不用,先创建出来,然后每次调用的时候,就不需要再判断了,节省了后每次调用的时候,就不需要再判断了,节省了运行时间。运行时间。3.73.7单例模式的优缺点单例模式的优缺点 2 2:线程安全:线程安全(1 1)从线程安全性上讲,不加同步的懒汉)从线程安全性上讲,不加同步的懒汉式是线程不安全的,比如说:有两个线程,式是线程不安全的,比如说:有两个线程,一个是线程一个是线程A A,一个是线程,一个是线程B B,它们同时调,它们同时调用用getInstancegetInstance方法,那就可能导致并发问方法,那就可能导致并发问题。如下示例:题。如下示例:程

42、序继续运行,两个线程都向前走了一步,程序继续运行,两个线程都向前走了一步,如下:如下:画个图说明一下,如图所示画个图说明一下,如图所示 通过上图的分解描述,明显可以看出,当通过上图的分解描述,明显可以看出,当A A、B B线线程并发的情况下,会创建出两个实例来,也就是程并发的情况下,会创建出两个实例来,也就是单例的控制在并发情况下失效了。单例的控制在并发情况下失效了。(2 2)饿汉式是线程安全的,因为虚拟机保证了只会)饿汉式是线程安全的,因为虚拟机保证了只会装载一次,在装载类的时候是不会发生并发的。装载一次,在装载类的时候是不会发生并发的。(3 3)如何实现懒汉式的线程安全呢?)如何实现懒汉式的线程安全呢?当然懒汉式也是可以实现线程安全的,只要加上当然懒汉式也是可以实现线程安全的,只要加上synchronizedsynchronized即可,如下:即可,如下:public static synchronized Singleton getInstance()public static synchronized Singleton getInstance()但是这样一来,会降低整个访问的速度,而且每但是这样一来,会降低整个访问的速度,而且每次都要判断,也确实是稍微慢点。次都要判断,也确实是稍微慢点。

展开阅读全文
部分上传会员的收益排行 01、路***(¥15400+),02、曲****(¥15300+),
03、wei****016(¥13200+),04、大***流(¥12600+),
05、Fis****915(¥4200+),06、h****i(¥4100+),
07、Q**(¥3400+),08、自******点(¥2400+),
09、h*****x(¥1400+),10、c****e(¥1100+),
11、be*****ha(¥800+),12、13********8(¥800+)。
相似文档                                   自信AI助手自信AI助手
百度文库年卡

猜你喜欢                                   自信AI导航自信AI导航
搜索标签

当前位置:首页 > 包罗万象 > 大杂烩

移动网页_全站_页脚广告1

关于我们      便捷服务       自信AI       AI导航        获赠5币

©2010-2024 宁波自信网络信息技术有限公司  版权所有

客服电话:4008-655-100  投诉/维权电话:4009-655-100

gongan.png浙公网安备33021202000488号   

icp.png浙ICP备2021020529号-1  |  浙B2-20240490  

关注我们 :gzh.png    weibo.png    LOFTER.png 

客服