保证一个类只有一个实例,并且提供一个全剧访问点
场景: 重量级的对象,不需要多个实例,比如说线程池,数据库链接吃
1.懒汉模式
使用再加载
设计问题
a.线程安全问题
b.double check 加锁优化
c.编译器 JIT cpu有可能进行指令重排序,导致使用尚未初始化的实力,可以通过添加volatile关键字修饰
对于volatile修饰字段可以防止指令重排
new 对象过程
//JIT会进行指令重排 或者cpu
// 1,分配空间
//2.初始化
//3.引用赋值
重排后顺序是132
单线程是没有影响的
但是多线程 线程一完成引用赋值但是没有初始化时候 线程2进来发现会产生空指针
可以采用volitle 便不会发生重排序
2.饿汉模式
public class HungrySingleton {public static void main(String[] args) {}public static HungrySingleton instance = new HungrySingleton();public static HungrySingleton getInstance() {return instance;}//类加载过程中,就完成了实力的初始化//接住了jvm类加载机制,保证实例的唯一性//类加载过程:// 1.加载二进制数据进内存中,生成class的数据结构// 2.连接 A验证 B准备 给类的静态变量赋默认值 C解析// 3.初始化 给类的静态变量赋予初始值}
3.静态内部类
//内部类单例模式 懒加载方式 不对类使用getInstance() 静态内部类就不会被加载class InnerClassSingleton {private static class InnerClass {private static InnerClassSingleton innerClassSingleton = new InnerClassSingleton();}public static InnerClassSingleton getInstance() {return InnerClass.innerClassSingleton;}}
利用类加载机制来保证线程安全
只有在实际使用中 才会触发类的初始化,所以也是懒加载的一种方式
4.反射攻击类
class EnumTest {public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {Constructor<EnumSingleton> constructor = EnumSingleton.class.getDeclaredConstructor(String.class);constructor.setAccessible(true);EnumSingleton enumSingleton = constructor.newInstance("INSTANCE",0);//报错 Exception in thread "main" java.lang.NoSuchMethodException: controller.EnumSingleton.<init>(java.lang.String)}}
5.枚举
public enum EnumSingleton {INSTANCE;public void print() {System.out.println(this.hashCode());}}class EnumTest {public static void main(String[] args) {EnumSingleton enumSingleton = EnumSingleton.INSTANCE;EnumSingleton enumSingleton1 = EnumSingleton.INSTANCE;System.out.println(enumSingleton == enumSingleton1);}}
