参考链接:
-
【狂神说Java】通俗易懂的23种设计模式教学(停更)_哔哩哔哩_bilibili
-
23种设计模式【狂神说】_狂神说设计模式_miss_you1213的博客-CSDN博客
1. 单例模式
参考链接:
-
【狂神说Java】单例模式-23种设计模式系列_哔哩哔哩_bilibili
-
JAD Java Decompiler Download Mirror
1.1 饿汉式单例
package com.study.singleton; /** * @ClassName HungryMan * @Description 饿汉式单例模式【不安全】 * @Author Jiangnan Cui * @Date 2023/3/20 22:24 * @Version 1.0 */ public class HungryMan { /** * 缺点:类加载期间就创建对象,容易造成资源浪费。即:当该类中放置了很多资源时,最开始加载可能会浪费空间,因为加载了也不使用。 */ private byte[] data1 = new byte[1024*1204]; private byte[] data2 = new byte[1024*1204]; private byte[] data3 = new byte[1024*1204]; private byte[] data4 = new byte[1024*1204]; private byte[] data5 = new byte[1024*1204]; /** * 私有构造方法限制产生多个对象 */ private HungryMan() { } /** * 最开始就创建对象,保证只有一个对象 */ private static final HungryMan HUNGRY_MAN = new HungryMan(); /** * 通过该方法获得实例对象 * @return */ public static HungryMan getInstance(){ return HUNGRY_MAN; } }
1.2 懒汉式单例
package com.study.singleton; /** * @ClassName LazyMan * @Description 懒汉式单例模式:用的时候再创建【不安全】 * 单线程下安全,多线程下存在并发安全问题 * @Author Jiangnan Cui * @Date 2023/3/20 22:33 * @Version 1.0 */ public class LazyMan { /** * 私有构造方法限制产生多个对象 */ private LazyMan(){ // 此处为了测试多线程并发安全问题 System.out.println(Thread.currentThread().getName() + " is ok"); } private static LazyMan lazyMan = null; /** * 通过该方法获得实例对象 * @return */ public static LazyMan getInstance(){ if (lazyMan == null) { lazyMan = new LazyMan(); } return lazyMan; } public static void main(String[] args) { // 多线程并发时存在线程安全问题 for (int i = 0; i < 10; i++) { new Thread(()->{ LazyMan.getInstance(); }).start(); } /** * 输出的一个结果举例: * Thread-0 is ok * Thread-3 is ok * Thread-2 is ok * Thread-1 is ok */ } }
1.3 懒汉式单例-DCL
package com.study.singleton; import com.sun.org.apache.bcel.internal.generic.I2B; import java.lang.reflect.Constructor; import java.lang.reflect.Field; /** * @ClassName LazyMan2 * @Description 懒汉式单例模式+双重锁校验优化+防止指令重排:DCL懒汉式【不安全】】 * 解决多线程下存在并发安全问题 * @Author Jiangnan Cui * @Date 2023/3/20 22:33 * @Version 1.0 */ public class LazyMan2 { private static boolean secret = false;// 红绿灯 /** * 私有构造方法限制产生多个对象 */ private LazyMan2(){ // 解决反射破坏单例问题 synchronized (LazyMan2.class) { if (secret == false) { secret = true; } else { throw new RuntimeException("不要试图使用反射破坏异常!"); } } // 此处为了测试多线程并发安全问题 System.out.println(Thread.currentThread().getName() + " is ok"); } /** * 加volatile防止指令重排 */ private volatile static LazyMan2 lazyMan2 = null; /** * 通过该方法获得实例对象 * @return */ public static LazyMan2 getInstance(){ if (lazyMan2 == null) { synchronized (LazyMan2.class) { if (lazyMan2 == null) { /** * new对象的过程中,不是一个原子性操作 * 1.分配内存空间 * 2.执行构造方法,初始化对象 * 3.把这个对象指向这个空间 * * CPU指令重排:1、3、2,此时lazyMan2还没有完成构造,需要加volatile保证指令不重排 */ lazyMan2 = new LazyMan2(); } } } return lazyMan2; } public static void main(String[] args) throws Exception { /** * 反射可以破坏单例 */ // LazyMan2 instance1 = LazyMan2.getInstance(); // 2.再次调用反射:获取字段,无视私有 Field secret = LazyMan2.class.getDeclaredField("secret"); secret.setAccessible(true);//无视私有构造器 // 1.利用反射 Constructor<LazyMan2> declaredConstructor = LazyMan2.class.getDeclaredConstructor(null); // 无视私有构造器 declaredConstructor.setAccessible(true); // 创建新对象 LazyMan2 instance1 = declaredConstructor.newInstance(); // 3.重新设置 secret.set(instance1, false); // 再次利用反射创建对象 LazyMan2 instance2 = declaredConstructor.newInstance(); System.out.println("instance1 = " + instance1); System.out.println("instance2 = " + instance2); } }
1.4 静态内部类
package com.study.singleton; /** * @ClassName StaticInnerClass * @Description 静态内部类单例模式【不安全】 * @Author Jiangnan Cui * @Date 2023/3/20 23:31 * @Version 1.0 */ public class StaticInnerClass { private StaticInnerClass(){ } public static StaticInnerClass getInstance(){ return InnerClass.STATIC_INNER_CLASS; } public static class InnerClass { private static final StaticInnerClass STATIC_INNER_CLASS = new StaticInnerClass(); } }
1.5 枚举
package com.study.singleton; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; /** * @ClassName SingleEnum * @Description enum本身也是一个class类,jdk 1.5就有了 * @Author Jiangnan Cui * @Date 2023/3/20 23:18 * @Version 1.0 */ public enum SingleEnum { INSTANCE; public SingleEnum getInstance(){ return INSTANCE; } } class Test{ public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { SingleEnum instance1 = SingleEnum.INSTANCE; Constructor<SingleEnum> declaredConstructor = SingleEnum.class.getDeclaredConstructor(String.class, int.class);//注意此处并不是无参构造方法,实际有String、int两个参数,要通过反编译工具jad.exe才能验证 declaredConstructor.setAccessible(true); // SingleEnum instance2 = SingleEnum.INSTANCE; SingleEnum instance2 = declaredConstructor.newInstance(); System.out.println("instance1 = " + instance1); System.out.println("instance2 = " + instance2); } } // Exception in thread "main" java.lang.IllegalArgumentException: Cannot reflectively create enum objects at java.lang.reflect.Constructor.newInstance(Constructor.java:417) at com.study.singleton.Test.main(SingleEnum.java:26)
javap -p 类名.class反编译:
jad.exe反编译结果:
待完善