设计模式
设计模式概述
设计模式(Design pattern),是一套被反复使用、经过分类编目的、代码设计经验的总结,使用设计模式是为了可重用代码、保证代码可靠性、程序的重用性。
1995 年,GoF(Gang of Four,四人组)合作出版了《设计模式:可复用面向对象软件的基础》一书,共收录了 23 种设计模式。
总体来说设计模式分为三大类:
创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
单例设计模式
单例模式又叫做单态模式,保证一个类仅有一个实例。
/*
* 饿汉式
* 保证次类的对象,具有唯一性
* 单例
* 1: 私有修饰构造方法
* 2: 创建本类对象,自己new自己
* 3: 公共方法,返回本类对象
*/
public class Single {
private Single() {}
private static Single s = new Single();
public static Single getInstnce() {
return s;
}
}
/*
* 懒汉式
* 保证次类的对象,具有唯一性
* 单例
* 1: 私有修饰构造方法
* 2: 创建本类对象,自己new自己
* 3: 公共方法,返回本类对象
*/
public class Single {
private Single() {}
private static Single s = null;
public static Single getInstnce() {
if(s == null) {
s = new Single();
}
return s;
}
}
/*
* 保证次类的对象,具有唯一性
* 单例
* 1: 私有修饰构造方法
* 2: 创建本类对象,自己new自己
* 3: 公共方法,返回本类对象
*
* 懒汉式 : 出现线程安全问题
* if(s==null)
* 多个线程(CPU挂起)
* s = new Single();
*/
public class Single {
private Single() {}
private static Single s = null;
public static synchronized Single getInstnce() {
if(s == null) {
s = new Single();
}
return s;
}
}
/*
* 保证次类的对象,具有唯一性
* 单例
* 1: 私有修饰构造方法
* 2: 创建本类对象,自己new自己
* 3: 公共方法,返回本类对象
*
* 懒汉式 : 出现线程安全问题
* 同步方法之后,不满意
* 锁太重
*
* 如果一个线程,运行后,变量s 不是空,对象地址
* 当下一个线程 ,再运行没有必要在拿锁,再判断,直接 return
* 双重判断
*
*
*/
public class Single {
private Single() {}
private static volatile Single s = null;
public static Single getInstnce() {
if(s == null) {
synchronized(Single.class) {
if(s == null) {
s = new Single();
}
}
}
return s;
}
}
面试题 (半初始化)
单例设计模式DCL,成员变量,是否需要添加关键字 volatile 加,必须加
volatile(修饰符) 写在成员变量, 防止指令重排序
创建对象的指令 :
- 堆内存开辟空间 (地址)
- 初始化自己的成员变量 private int a = 1
- 先默认值0
- 定义值
- 调用构造方法
- 地址传递给引用变量
以上指令,按照顺序进行,如果CPU出现了指令上乱序, 出现对象没有创建完成,先将内存的地址赋值到引用变量
如果另一个线程执行,带走变量,没有创建完成的对象!!
面试题 (volatile)
保证内存的可见性 : 内存中的数据,只要有1个线程进行了更新,其他线程都会读取到最新的数据
面试题(JDK锁升级)
一个对象,做为同步锁来使用,锁会有四个状态
- 无锁 : 被创建, new出来的时候,无锁状态
- 偏向锁 : 进入同步的时候,升级为偏向锁,偏向某个线程,最先执行的那个
- 轻量锁 : CAS (CompareAndSwap) 自旋锁
- 线程读取数据,修改后,和原数据对比,无变化就保存
- 线程读取数据,修改后,和原数据对比,有变化就从新读取数据
- CAS锁,出现ABA的问题,解决思想 version, 版本号
- 重锁
- CAS锁满足一定条件,升级为重锁
- 一个线程自旋的次数超过10次
- 正在自旋的线程个数,超过CPU线程数的一半
- 两个条件,满足一个,升级为重锁
- 重锁是效率底下,要和操作系统交互,将线程全部进入到CPU的阻塞队列
- 调用了wait() notify() 直接升级为重锁
- CAS锁满足一定条件,升级为重锁