单例模式学习笔记
概念:
系统中只有一个该类的一个对象实例
使用场景
redis
连接对象Spring IOC
容器中的默认beanSpringBoot
中的controller
、service
、dao
层通过Autowire
的依赖注入对象默认都是单例的。
懒汉模式
-
用途:懒加载、延时加载,延迟创建对象
-
实现方式:
- 私有化构造函数,不能随便new对象。
- 对外提供一个获取对象实例的方法。
-
详细代码
package com.example.test.single; /** * @author 晓果冻 * @version 1.0 * @date 2021/10/21 21:47 */ public class SingletonLazy { public static SingletonLazy instance; /** * 构造函数私有化,外界不能通过new创建该对象 */ private SingletonLazy() { } /** * 对外只提供一个创建实例的方法,多线程下不安全 * * @return */ public static SingletonLazy getInstance() { if (instance == null) { instance = new SingletonLazy(); } return instance; } /** * 通过synchronized枷锁保证多线程下的单例 * 但synchronized开销大,又是在方法级别上控制的 * * @return */ public static synchronized SingletonLazy getInstance02() { if (instance == null) { instance = new SingletonLazy(); } return instance; } /** * 这是否安全,instance = new SingletonLazy(); 并不是原子性操作 * 1、分配空间给对象 * 2、在空间内创建对象 * 3、将对象赋值给引用instance * * 假如线程 1-》3-》2顺序,会把值写会主内存,其他线程就会读取到instance最新的值,但是这个是不完全的对象 * (指令重排) * @return */ public static SingletonLazy getInstance03() { if (instance == null) { //假设此时同时有A、B线程满足到达这里 synchronized (SingletonLazy.class) { //加锁 控制只有一个线程占有此锁 if (instance == null) { //涉及双重锁检查,如果现在堆中分配了空间,堆是线程共享的,所以其他线程都可以读到此空间内容 instance = new SingletonLazy(); } } } return instance; } /** * volatile是Java提供的关键字,它具有可见性和有序性, * 指令重排序是JVM对语句执行的优化,只要语句间没有依赖,那JVM就有权对语句进行优化 * 禁止了指令重排 */ private static volatile SingletonLazy volatileInstance01; public static SingletonLazy getInstance04() { //第一重检查 if (volatileInstance01 == null) { // A、B ,锁定 synchronized (SingletonLazy.class) { //第二重检查 if (volatileInstance01 == null) { volatileInstance01 = new SingletonLazy(); } } } return volatileInstance01; } }
饿汉模式
-
用途:因为饿,所以急切需要对象。提前创建对象
-
实现方式:
- 私有化构造函数,不能随便new对象。
- 对外提供一个获取对象实例的方法。
-
详细代码
package com.example.test.single; /** * @author cgd * @date 2021/10/27 17:54 */ public class SingletonHungry { private static SingletonHungry instance = new SingletonHungry(); private SingletonHungry() { } public static SingletonHungry getInstance() { return instance; } }
俩种方式对比
- 饿汉
- 优点:实现简单,没有多线程问题
- 缺点:不论是否使用,实例对象一直占用这段空间
- 懒汉
- 优点:按需使用,不浪费空间
- 缺点:实现复杂
- 如何选择:
- 对象不大,且创建不复杂,直接使用饿汉
- 其他情况使用懒汉
评论区