创建型模式
单例模式
饿汉式
// 问题1:为什么加 final// 问题2:如果实现了序列化接口, 还要做什么来防止反序列化破坏单例:readResolve()方法public final class Singleton implements Serializable {// 问题3:为什么设置为私有? 是否能防止反射创建新的实例?private Singleton() {}// 问题4:这样初始化是否能保证单例对象创建时的线程安全?private static final Singleton INSTANCE = new Singleton();// 问题5:为什么提供静态方法而不是直接将 INSTANCE 设置为 public, 说出你知道的理由public static Singleton getInstance() {return INSTANCE;}public Object readResolve() {return INSTANCE;}}
低性能 懒汉式
public final class Singleton {private Singleton() { }private static Singleton INSTANCE = null;// 分析这里的线程安全, 并说明有什么缺点 ==> 无论如何,都得等待所释放public static synchronized Singleton getInstance() {if( INSTANCE != null ){return INSTANCE;}INSTANCE = new Singleton();return INSTANCE;}}
DCL 优化 懒汉式
什么是双重检查锁:
双重检查锁是一个对单例模式的优化,具体做了如下步骤:
在synchronized外边,做了一个空判断,好处如下:
- (相对于直接synchronized)避免用户态到内核态的一个消耗,即不用等锁释放,进行上下文切换
new 对象的时候需要经过如下步骤:
- 分配内存空间
- 对象初始化
- instance 指针指向内存空间
不使用 volitale修饰的话,可能会出现一个指令重排,会导致如下结果
- 如果先执行 instance 指针指向内存空间:
A线程刚执行到new对象,B线程刚判断实例是否为空(即synchronized方法前).
B线程此时拿到的是没有初始化的结果(只分配了空间,还没有调用构造方法,拿到了个半成品)
- 为什么加volitale能拿到一个正常的结果:
- volitale只能保证单个JVM指令的原子性和可见性
- 真正的作用:
- 在 new 对象前边添加 store store屏障
- 在 new 对象后边添加 store load 屏障
- 最终保证 new 对象的过程,对外不可乱序获取,因此保证了线程安全性
public final class Singleton {private Singleton() { }// 问题1:解释为什么要加 volatile ?//==>避免重排序后,拿到的引用,只是分配了内存空间,但是没有来得及调用构造方法!private static volatile Singleton INSTANCE = null;// 问题2:对比实现3, 说出这样做的意义// ==> 创建好后,大家都直接用就行了,不像未优化的版本,就算已经创建了,也得等待锁public static Singleton getInstance() {if (INSTANCE != null) return INSTANCE;synchronized (Singleton.class) {// 问题3:为什么还要在这里加为空判断, 之前不是判断过了吗//==>若无:t1 t2都判断外面的实例为null,t1拿到锁创建实例后,t2又进来创建一个.if (INSTANCE != null) { // t2return INSTANCE;}INSTANCE = new Singleton();return INSTANCE;}}}
静态内部类 懒汉式
public final class Singleton {private Singleton() { }// 问题1:属于懒汉式还是饿汉式(懒汉式,类的创建是懒汉式,第一次加载类时,才会初始化)private static class LazyHolder {static final Singleton INSTANCE = new Singleton();}// 问题2:在创建时是否有并发问题(JVM负责的类加载是能够保证线程安全的)public static Singleton getInstance() {return LazyHolder.INSTANCE; //在这类调用类}}
工厂方法模式
建造者模式
结构型模式
适配器模式
代理模式
装饰者模式
单线程线程池返回值使用装饰器模式进行了包装
