定义

确保一个类只有一个实例,而且自行实例化并向整个系统提供这个实例

特点

通过private修饰类的构造,自行实例化,同时对外提供获取实例的方法,饿汉式的特点使用private static final 修饰对象实例化,static final修饰的变量,jvm启动完成对象在内存已经初始化完成,private修饰构造,客户端无法创建新的实例,客户端通过调用获取对象方法时,对象在内存中已经存在,直接返回对象实例

懒汉式的特点是初始化对象为null,private修饰构造,客户端无法创建新的实例,客户端通过调用获取单例对象方法,方法中判断对象是否已经初始化,如果为null则需要先在内存中创建对象实例,再返回给客户端,饿汉式需要使用double-check + volatile解决线程不安全问题

优点

减少内存开销,避免了频繁的对象创建、销毁上性能问题

系统共享资源的访问可以使用单例模式

单例模式可以很好的管理对象的生命周期,如spring容器对bean的管理默认就是单例的

缺点

扩展性非常差,如果有修改,只能修改本类

手撕单例

饿汉式

/**

* 饿汉式jvm加载对象已经初始化完成,不存在线程问题

*/

示例代码

懒汉式

/**

* 懒汉式,使用时才初始化对象,线程不安全的,解决方案:

* 如果synchronized修饰在静态方法上,锁范围作用在类上,会导致线程阻塞,即使已经实例化也会阻塞,

* 通过方法内第一重判断后使用同步代码块,解决并发问题,第二重判断防止线程不安全情况发生时,对象重复实例化

* 双重锁,双重锁锁对范围在方法内,当锁释放时,执行效率更快

* 但是在使用双重锁时,初始化对象内存和将对象引用指向内存会重排序,需要使用volatile修饰对象,阻止指令重排序

示例1

示例2

扩展volatile

1. volatile关键字修饰的类的成员变量/类的静态成员变量内存可见,读写操作直接操作主内存,同时阻止指令重排序,内存屏障后的指令不会在内存屏障前的指令先执行,内存屏障前后两部分内指令各自的执行顺序不作保证

2. volatile会强制将工作内存中的值修改刷新到主内存

3. 如果是写操作,会导致其他线程中的工作内存中的变量副本失效

第一个操作锁普通读写时,第二个操作时volitile写时,不能重排序

第一个操作是valatile读时,第二个操作不管是什么都不能重排序

第一个操作是volitile写时,第二个操作时volatile读或volitile写时,不能重排序

加客服微信:qiushu0517,开通VIP下载权限!