一,初识单例模式
包括:定义,结构,参考实现
二,体会单例模式
包括:场景问题,不用模式的解决方案,使用模式的解决方案
三,理解单例模式
包括:认识单例模式,懒汉式,饿汉式实现,延迟加载的思想,缓存的思想,Java中缓存的基本实现,利用缓存来实现单例模式,单例模式的优缺点,
四,思考单例模式
包括:单例模式的本质,何时选用
一,初识单例模式
1,定义
保证一个类仅有一个实例,并提供一个访问它的全局访问点
2,结构和说明
负责创建Singleton类自己的唯一实例,并提供一个getInstance的方法,让外部来访问这个类的唯一实例
二,体会单例模式
读取配置文件内容
a,不用模式
代码详见 git@github.com:qinixiangyang111/design.git 中example1
存在的问题:
在系统运行期间,系统会存在很多个AppConfig的实例对象,这会很严重的浪费系统资源。
上面的描述抽象一下:在系统运行期间,某个类只需要一个类的实例就可以了,应该怎么实现?
b,使用模式
代码详见example2包
用的是饿汉式
三,理解单例模式
1,单例模式的功能
用来保证这个类在运行期间只会创建一个类的实例,并提供一个全局唯一访问这个类实例的访问点
2,单例模式的范围
是一个ClassLoader及其子ClassLoader的范围(一个虚拟机的范围)
3,单例模式的命名
一般建议单例模式方法的命名 getInstance(),方法可以加参数,
4,懒汉式和饿汉式的实现
懒汉式: example4下
饿汉式:example3下
分析这两种方法的问题
-
从时间空间上看:
-
懒汉式以时间换空间(需要做判断)
-
饿汉式以空间换时间(类加载的时候就创建了,这种做法相对较好,如果一定会用的话)
-
从线程安全
- 懒汉式:不安全
- 饿汉式:安全的(虚拟机保证)
5,延迟加载的思想
延迟加载:开始的时候不要加载资源或数据,等到必须要用的时候才加载,Lazy Load,目的是尽量节约资源
(懒汉式体现这种思想)
6,缓存思想
单例模式懒汉式还体现了缓存的思想
如果某些资源或数据被频繁使用,可以把这些数据缓存到内存中,每次操作的时候先从缓存中去找,缓存是典型的以空间换时间。
7,java缓存的基本实现
使用集合的方式(List或者Map)
代码详见example5
a,定义一个存放缓存数据的容器
b,从缓存中获取数据的做法
- 先从缓存里面取值
- 判断缓存中是否有值
- 如果有值直接返回使用
- 如果没有,获取相应的数据,并放到缓存中(重点,保证下一次使用)
//web中scope===》数据缓存的范围,request,
//<jsp: useBean name=“aa” class=“cn.javass.Amodel” scope=“request”>
//就是缓存的思想 Object obj=request.getAttibute(“aa”);
8,利用缓存实现单例模式(不推荐)代码详见example6
9,单例模式的优缺点
a,时间和空间 饿汉式空间换时间。懒汉式时间换空间
b,线程安全。
(1)不加同步的懒汉式是线程不安全的
(2)饿汉式是线程安全的
(3)双重检查加锁
并不是每次进入getInstance方法都需要同步,而是先不同步,进入方法后,检查实例是否存在,如果不存在才进入下面的同步块,这是第一重检查,进入同步块之后,再次检查实例是否存在,如果不存在就在同步情况下创建一个实例,这是第二重检查,这样一来,只需同步一次,从而减少多次在同步情况下进行判断所浪费的时间。代码详见example8
volatile:被volatile修饰的变量并不是存在本地线程缓存,而是放在共享的内存进行的操作,
(4)如何保证懒汉式是线程安全的?加synchronized
10,
内部类创建单例模式,代码详见example7
11,单例和枚举
单元素的枚举类型,成为实现单例模式的最佳方法
12,单例模式的本质
控制实例的数目(思考怎么可以保证实例的数量为指定的见example10)
13,何时选用单例模式
a,当需要类的实例只能有一个,客户只能从一个全局访问点访问它的时候,可以选用单例模式