单例模式设计
目标:
1. 饿汉模式
2. 懒汉模式
3. 饿汉模式优化
目录
饿汉模式
懒汉模式
懒汉模式优化
饿汉模式
由名字我们就可以知道 "饿汉" 嘛,就比较急切,在类加载的时候就创建实例:
1. 写一个类,在本类中构造实例,用static修饰,直接创建出来(提供一个现有的实例)
2. 在本类中写一个方法获取到上面的实例
3. 将这个类的构造方法设置为私有的,让外部不能 new 这个对象
//饿汉模式:直接 static 一个实例(线程安全)//期望这个类只能有一个实例
public class Demo1 {//只构造一个实例private static Demo1 instance = new Demo1();//获取这个实例public static Demo1 getInstance() {return instance;}//把构造方法设置为私有 外部不能 new 这个类对象private Demo1(){}
}
懒汉模式
由名字我们就可以知道 "懒汉" 嘛,就比较从容~,它是等到有人调用的时候再创建实例:
1. 写一个类,在本类中构造实例,用static修饰,赋值为空(等待有人调用)
2. 在本类中写一个方法获取到上面的实例
3. 将这个类的构造方法设置为私有的,让外部不能 new 这个对象
//懒汉模式://期望这个类只能有一个实例
public class Demo2 {private static Demo2 instance = null;//获取这个实例public static Demo2 getInstance() {if (instance == null) {instance = new Demo2();}return instance;}//把构造方法设置为私有 外部不能 new 这个类对象private Demo2(){}}
懒汉模式优化
根据上面的 "懒汉模式" 和 "饿汉模式"。我们可以知道,懒汉模式,它只是负责读取,没有修改。而 " 饿汉模式 " 是既读取,也进行修改。所以来说, "懒汉模式" 是线程安全的, "饿汉模式" 是线程不安全的。
所以为了使 " 饿汉模式" 线程安全,我们做以下几步操作:
1. 进行加锁:怎么加呢???
我们应该给整个 if 语句进行加锁,防止两个线程同时调用的时候都为 null ,从而就实例化了两个。
//懒汉模式优化
public class Demo3 {private static volatile Demo3 instance = null;//获取这个实例public static Demo3 getInstance() {synchronized (Demo3.class) {if (instance == null) {instance = new Demo3();}}return instance;}//把构造方法设置为私有 外部不能 new 这个类对象private Demo3(){}}
2. 线程安全是解决了,但是呢?
我们会发现,后续我们每次调用 getInstance() 的时候,都必须进行加锁一次,我们也没必要每次都加锁(加锁其实也是很大的开销,可能会使好多线程阻塞等待,影响了效率),当不为 null 的时候,就不用加锁了,这样就迎刃而解了~~~
//懒汉模式优化
public class Demo3 {private static volatile Demo3 instance = null;//获取这个实例public static Demo3 getInstance() {if (instance == null) {synchronized (Demo3.class) {if (instance == null) {instance = new Demo3();}}}return instance;}//把构造方法设置为私有 外部不能 new 这个类对象private Demo3(){}}