单例模式(Singleton)

单例模式(Singleton)

image1
分为单例类(只能创建一个实例的类)和访问类(test)
—————————-华丽分隔符————————————

实现方式:

一 饿汉式 : 类加载时就会创建单实例对象造成一定的浪费

在类内部创建好该类的对象, 对外提供获取实例的方法
成员变量并赋值/静态代码块赋值

image2

Enum—>有限集合

1
2
public enum Singleton {
INSTANCE; // 唯一实例
1
2
3
4
5
public void doSomething() {
System.out.println("做点事情");
}
}
Singleton.INSTANCE.doSomething();

二 饱汉式 : 用类名.getInstance时才创建, 但是多线程会出现并发创建多个实例的问题
有两种方法解决: 1.volatile + double check+ synchronized 2.静态内部类

其中静态内部类:
原理:
image3

要点
a. 静态内部类属于外部类本身,不依赖外部类实例

  • 所以同一个外部类的多个实例共享同一个静态内部类。

b. 静态内部类的类加载和静态成员初始化是延迟的

  • 只有第一次访问静态内部类时,JVM 才会加载类并初始化静态字段(懒加载)
  • JVM 保证类加载和静态字段初始化的线程安全,因此单例实例只会创建一次,无需额外加锁。

—————————-华丽分隔符————————————
单例模式被破坏情形:
1.反序列化
image4
原因:

  • 反序列化时,JVM 会创建一个全新的对象,而不是调用你单例类的 getInstance() 方法
  • 即使构造器是私有的,也无济于事
  • 所以序列化破坏了单例模式 → 原来的单例可能被复制多次

2.反射

  • 反射(Reflection)允许你访问类的 私有构造器
  • 即使单例类把构造器 private,反射也能绕过访问控制:

解决方案:
1.加一个readObject()方法用以返回内部类定义的实例.
这样jvm会先看是否有readObject方法
2.enum

java中单例的例子:
Runtime
image5