设计模式 - 单例模式(一)理论
单例模式
作用:在全局范围内只创建该类的一个对象实例。
使用场景:
1、spring大多数对象都是单例存在的。一般被spring管理的bean,都是业务对象,不是数据对象。
2、数据源等信息
单例的实现方式分为两种:
饿汉式:面试不会问这种方式,因为该种方式线程是安全的。
懒汉式(也叫延迟加载):面试重灾区,因为该种方式去实现单例,会存在线程安全问题。需要小心处理。
饿汉式和懒汉式的区别:
1.饿汉式会造成资源浪费,懒汉式不会。
2.懒汉式会存在线程安全,饿汉式不会。
单例的实现步骤:
1.构造私有
2.私有静态成员变量(如果声明静态成员变量时就进行初始化,则是饿汉式,否则是懒汉式)
3.公开静态成员方法,获取静态成员变量
单例解释知识
- 类的加载时机(类加载)(类1)
1.new Student
2.访问类的静态成员时
- JVM的安全机制:(类1)
当一个类被JVM加载的时候,该类的加载过程是线程安全的,也就是说,相当于JVM对该过程加锁了。
- 线程执行
单CPU的情况,线程在执行时,宏观上是并行的,其实微观上是串行的,线程是通过分配CPU的时间片去执行的。
一个线程的执行需要被CPU分配好几次时间片才能执行完成。
- 理解一个对象在内存中的创建过程:Student student = new Student();
1.new 会触发类加载机制(已经被加载过的类不需要再次加载)
2.分配堆内存空间(相当于已经有内存地址)
3.将对象进行初始化(将成员变量初始化为0)
4.将对象引用地址赋值给栈空间中的变量
- 底层字节码的执行过程(有序性)
JVM的JIT即时编译器会对代码的执行过程进行优化,包含代码的执行顺序。
也就是说以上对象的创建过程,可能被JIT即时编译器优化为1-2-4-3(指令重排序)。
- 并发编程的三个特性:
原子性、有序性、可见性
原子性
主要针对的不是高级语言的原子性,而是字节码或者机器码的原子性操作。
new Student();//也不是原子性操作
i++;//不是原子性操作
1.先从局部变量表中获取i的值
2.将i的值加入到操作栈中
3.将操作栈中的i进行自加
4.将自加的i值放入操作栈
5.将操作栈的栈顶元素取出并放入局部变量表
如何保证原子性呢?
使用锁机制(synchronized和lock锁)
有序性
int x ;//1
boolean y;//2
x = 10;//3
y = false;//4
当x和y之间没有依赖性(happened-before原则),x和y的执行可以进行指令重排序(字节码指令);
int x= 10;
int y = x +2;
以上的代码不能进行指令重排序,因为y的值依赖于x,所以先要执行x这行代码
如何保证有序性呢?
volatile关键字的第一个作用:就是禁止被它修饰的变量相关操作进行指令重排序。
可见性