保证一个类只有一个实例,并且提供一个全剧访问点
场景: 重量级的对象,不需要多个实例,比如说线程池,数据库链接吃

1.懒汉模式

使用再加载
设计问题
a.线程安全问题
b.double check 加锁优化
c.编译器 JIT cpu有可能进行指令重排序,导致使用尚未初始化的实力,可以通过添加volatile关键字修饰
对于volatile修饰字段可以防止指令重排
image.png
new 对象过程
//JIT会进行指令重排 或者cpu
// 1,分配空间
//2.初始化
//3.引用赋值
重排后顺序是132
单线程是没有影响的
但是多线程 线程一完成引用赋值但是没有初始化时候 线程2进来发现会产生空指针
可以采用volitle 便不会发生重排序

2.饿汉模式

  1. public class HungrySingleton {
  2. public static void main(String[] args) {
  3. }
  4. public static HungrySingleton instance = new HungrySingleton();
  5. public static HungrySingleton getInstance() {
  6. return instance;
  7. }
  8. //类加载过程中,就完成了实力的初始化
  9. //接住了jvm类加载机制,保证实例的唯一性
  10. //类加载过程:
  11. // 1.加载二进制数据进内存中,生成class的数据结构
  12. // 2.连接 A验证 B准备 给类的静态变量赋默认值 C解析
  13. // 3.初始化 给类的静态变量赋予初始值
  14. }

只用在使用的时候才会被初始化

3.静态内部类

  1. //内部类单例模式 懒加载方式 不对类使用getInstance() 静态内部类就不会被加载
  2. class InnerClassSingleton {
  3. private static class InnerClass {
  4. private static InnerClassSingleton innerClassSingleton = new InnerClassSingleton();
  5. }
  6. public static InnerClassSingleton getInstance() {
  7. return InnerClass.innerClassSingleton;
  8. }
  9. }

利用类加载机制来保证线程安全
只有在实际使用中 才会触发类的初始化,所以也是懒加载的一种方式

只有在进行new 访问静态属性,

4.反射攻击类

  1. class EnumTest {
  2. public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
  3. Constructor<EnumSingleton> constructor = EnumSingleton.class.getDeclaredConstructor(String.class);
  4. constructor.setAccessible(true);
  5. EnumSingleton enumSingleton = constructor.newInstance("INSTANCE",0);
  6. //报错 Exception in thread "main" java.lang.NoSuchMethodException: controller.EnumSingleton.<init>(java.lang.String)
  7. }
  8. }

5.枚举

  1. public enum EnumSingleton {
  2. INSTANCE;
  3. public void print() {
  4. System.out.println(this.hashCode());
  5. }
  6. }
  7. class EnumTest {
  8. public static void main(String[] args) {
  9. EnumSingleton enumSingleton = EnumSingleton.INSTANCE;
  10. EnumSingleton enumSingleton1 = EnumSingleton.INSTANCE;
  11. System.out.println(enumSingleton == enumSingleton1);
  12. }
  13. }