目录
一 . 什么是单例模式
饿汉与懒汉模式介绍 :
二 . 饿汉模式
三 . 懒汉模式
单例模式 ---> 是一种经典的设计模式.(设计模式 : 类似于"棋谱" , java中的大佬们针对一些工作中常见的场景,总结出来的编写"套路").
单例 : 指的是单个实例(对象) , 一个程序中, 某个类,只可以创建出一个实例(对象),不能创建多个对象.
Java中的单例模式 , 通过借助Java语法, 保证某个类, 只能够创建出一个实例, 不能new出多个类.
Java 中的两个经典单例模式 :
1 . 饿汉模式
2 . 懒汉模式
饿汉 :
举个栗子吧 : 好比平常的脏衣服, 穿完后, 直接洗掉. (急迫)
懒汉 :
举个栗子 : 好比平常的脏衣服 , 脏了脱掉之后, 先不洗, 等下次没有干净衣服穿的时候, 我再去洗. (从容)
上述这两个栗子 : 放在现实生活中 , 肯定是饿汉更好, 脏了就洗, 不然衣服放哪儿都臭了.
而在计算机中 通常认为懒汉模式更好,效率更高 (非必要,不洗)
例如 : 打开一个硬盘上的文件,读取文件的内容,并显示出来.
饿汉 : 把文件所有内容都读到内存中,并显示
懒汉 : 只把文件读一小部分 , 把当前屏幕填充满 , 如果要翻页, 再去读其他文件内容, 如若不翻页, 那么内存就剩下来了.
如果文件非常大 10G !!!!! 采用饿汉方式, 文件打开可能要卡半天, 内存够不够还不知道.
如果采用懒汉, 每次我们加载一点,即不影响内存,也不影响我们去读.
先看代码实现 :
public class Singleton {
// 创建单一模式对象
private static Singleton instance = new Singleton();
//将构造方法的权限设置为private 为了确保单一模式实例的唯一性.
private Singleton() {}
//提供一个get方法 获取单一变量
public static Singleton getInstance() {
return instance;
}
}
测试类 :
public class Test {
public static void main(String[] args) {
Singleton instance = Singleton.getInstance();
System.out.println(instance);
}
}
饿汉模式 : 在想使用这个对象时, 直接使用这个早都准备好的类成员.
饿汉模式是不是线程安全的?
假设如果多个线程都去调用getInstance()
由于是进行读操作, 因此认为饿汉模式是线程安全的.
懒汉模式 : 非必要, 不创建
因此创建对象就是在调用getInstance时进行创建的.
先看这个代码 :
public class Singleton2 {
public static Singleton2 instance;
private Singleton2(){}
public static Singleton2 getInstance() {
if (instance == null) {
instance = new Singleton2();
}
return instance;
}
}
分析 : 等其他类去调用getInstance方法时 , 先判断instance是不是空的,如果为空,那么就创建一个对象, 如果不为空那么就返回当前的instance对象.
但 : 思考一个问题 , 如果在多个线程下呢?
因此为了确保线程安全 , 就要进行加锁操作.
public static Singleton2 getInstance() {
synchronized (Singleton2.class) {
if (instance == null) {
instance = new Singleton2();
}
}
return instance;
}
问题又来了 :
换个思考方向 : 因为instance 只需要被创建一次 , 加锁针对的是在instance == null 的情况下,多个线程同一时间执行 , 以防创建出多个对象 , 等instance创建出来之后 , 锁竞争还是存在,这样就影响了程序的执行效率, 后面的线程想要获得instance 对象 , 都要进行加锁解锁操作, 这是没有必要的, 因为instance 早已经创建出来了.
因此我们在加锁前面在加上一个 if 判定.
public static Singleton2 getInstance() {
if (instance == null) {
synchronized (Singleton2.class) {
if (instance == null) {
instance = new Singleton2();
}
}
}
return instance;
}
到这里还没有结束 :
指令重排序!!!!
解决 : 加上volatile 关键字
public class Singleton2 {
volatile public static Singleton2 instance;
private Singleton2(){}
public static Singleton2 getInstance() {
if (instance == null) {
synchronized (Singleton2.class) {
if (instance == null) {
instance = new Singleton2();
}
}
}
return instance;
}
}