设计模式作为开发(面试)必备(必考)知识, 我们还是要好好掌握. 掌握不好,那是因为你没有准备好小抄~
啥是小抄, 就是参考别人的答案,加上自己手抄.
小抄参考资源:
单例模式
先抄个 UML 图
单例模式的数据结构很简单,就是一个单一的示例对象
单例模式的特点
- 单一实例
- 由自己内部创建
- 提供所有对象唯一访问实例
1、饿汉式单例
很奇怪的命名方式, 咱也不知道为啥这样叫,咱也不敢问,先抄吧~
public class SimpleSingleton {
//静态对象,在对象初始化时,进行创建
private static SimpleSingleton instance = new SimpleSingleton();
private SimpleSingleton() {
}
//返回已经创建好的实例对象
public static SimpleSingleton getInstance() {
return instance;
}
}
复制代码
饿汉式
其实是一种比较形象的称谓。既然饿,那么在创建对象实例的时候就比较着急,饿了嘛,于是在装载类的时候就创建对象实例。(抄的)
在类加载过程中, 当我们在初始化对象时, 会将对象中的静态属性初始化,因此这里主要时利用了 类加载的相关特性,从而达到了单例的效果.
特点
- 空间换时间 -- 程序启动即存在(容易浪费内存),节省使用时创建时间(感觉节省不了多少)--弊端较大
- 线程安全 -- 利用类加载进行初始化(只会初始化一次静态对象),线程安全
2、懒汉式单例
咱也不知道该怎么调侃这个命名,先抄就对了~
public class LazySingleton {
//先不初始化了, 节省点空间
private static LazySingleton instance;
private LazySingleton() { }
//加了个锁,排队访问吧 弟弟
public static synchronized LazySingleton getInstance() {
if (instance == null) {
instance = new LazySingleton();
}
return instance;
}
}
复制代码
参考资料(答案)里面有个非线程安全的懒汉模式,那个就是个弟弟,送命题,不抄
懒汉式
其实是一种比较形象的称谓。既然懒,那么在创建对象实例的时候就不着急。会一直等到马上要使用对象实例的时候才会创建,懒人嘛,总是推脱不开的时候才会真正去执行工作,因此在装载对象的时候不创建对象实例。(也是抄的)
特点
- 时间换空间 - 只有在使用时,才会初始化.避免浪费空间资源
- 低并发 -
synchronized
将疯狂请求的弟弟一个个安排在门口,响应缓慢
3、双重检测锁单例(DoubleCheckLock)
也不知道这个英语有没有拼错,没得抄只能蒙一下了,万一对了呢~
public class DCLSingleton {
//volatile 内存可见,就是可以实时查看到更新
private volatile static DCLSingleton instance = new DCLSingleton();
private DCLSingleton() {
}
public static DCLSingleton getInstance() {
if (instance == null) {
//妹妹进来了,安排好,就那么一次机会 好好珍惜
synchronized (DCLSingleton.class) {
//如果进来了个弟弟,撵出去
if (instance == null) {
//初始化好
instance = new DCLSingleton();
}
}
}
return instance;
}
}
复制代码
双重检查加锁
机制指的是:并不是每次进入getInstance方法都需要同步,而是先不同步,进入方法后,先检查实例是否存在,如果不存在才进行下面的同步块,这是第一重检查,进入同步块过后,再次检查实例是否存在,如果不存在,就在同步的情况下创建一个实例,这是第二重检查。这样一来,就只需要同步一次了,从而减少了多次在同步情况下进行判断所浪费的时间。(还是抄的)
这个模式,主要依赖于 volatile
关键字.
volatile
关键字的作用是: 它所修饰的变量,在发生变化时,会直接写入内存,与其他线程共享,从而确保在多线程下能正确获取该变量的值
特点
资源利用率高
- 解决了懒汉模式
中对方法加锁的尴尬情况有缺陷
- 高并发环境下也有一定的缺陷,虽然发生的概率很小
4、 静态内部类单例模式(Lazy initialization holder class)
这次名字英语抄对了~逼格上来了~
public class LIHCSingleton {
private LIHCSingleton() {
}
//内部类,类加载过程中,不会初始化
private static class SingletonHolder {
private static LIHCSingleton instance = new LIHCSingleton();
}
public LIHCSingleton getInstance() {
//调用内部类时,进行初始化
return SingletonHolder.instance;
}
}
复制代码
静态内部类单例模式
- 与饿汉模式类似,通过JVM类加载机制实现了线程安全的单例模式,并且通过静态内部类延迟加载机制,解决了 饿汉模式中出现的弊端.(自己写的)
特点
饿汉模式
的优点都有- 线程安全
- 资源利用率高
- 就很棒~
相关知识
什么是类级内部类?
-
简单点说,类级内部类指的是,有static修饰的成员式内部类。如果没有static修饰的成员式内部类被称为对象级内部类。
-
类级内部类相当于其外部类的static成分,它的对象与外部类对象间不存在依赖关系,因此可直接创建。而对象级内部类的实例,是绑定在外部对象实例中的。
-
类级内部类中,可以定义静态的方法。在静态方法中只能够引用外部类中的静态成员方法或者成员变量。
-
类级内部类相当于其外部类的成员,只有在第一次被使用的时候才被会装载。
5、枚举单例
终于快抄完了,酥服
public enum EnumSingleton {
singleton;
public void excute(){
//todo 做点啥都行, 你说了算
}
}
复制代码
默认枚举实例的创建是线程安全的,并且在任何情况下都是单例.(强,无敌)
《Effective Java》中有写到: 单元素的枚举类型已经成为实现Singleton的最佳方法.
使用枚举来实现单实例控制会更加简洁,而且无偿地提供了序列化机制,并由JVM从根本上提供保障,绝对防止多次实例化,是更简洁、高效、安全的实现单例的方式。
总结
三分靠打拼,七分天注定,剩下的90分, 你们加油哦~骚年