JUC并发编程学习笔记 (10)

代码示例 正常DCL public class DCLTest { //私有化构造函数 private DCLTest() { } /** * 我们之所以要对双重检查加锁的单例模式的单例对象加volatile关键字, * 是因为我们在进行创建单例对象时并不是一个原子操作-》 INSTANCE = new DCLTest(); * 创建一个对象有大概一下3个主要步骤,如果我们没有加volatile关键字修饰禁止指令重排的话,可能拿到的是一个还没有完成构件的对象 * 1. 分配内存空间 * 2、执行构造方法,初始化对象 * 3、把这个对象指向这个空间 * 123 * 132 A * B * 此时DCLTest还没有完成构造 * */ private static volatile DCLTest INSTANCE; public static DCLTest getInstance() { if (INSTANCE == null) { synchronized (DCLTest.class) { if (INSTANCE == null) { INSTANCE = new DCLTest();// 不是一个原子性操作 } } } return INSTANCE; } public static void main1(String[] args) { DCLTest instance1 = DCLTest.getInstance(); DCLTest instance2 = DCLTest.getInstance(); System.out.println(instance1); System.out.println(instance2); } /** * com.lai.springbootdemo.pattern.DCLTest@a09ee92 * com.lai.springbootdemo.pattern.DCLTest@a09ee92 */ } DCL加反射 public class DCLReflectTest { private static boolean singletonFlag = false; //私有化构造函数 private DCLReflectTest() { //在构造器上加约束,避免反射破坏单例 synchronized (DCLReflectTest.class) { if (singletonFlag == false) { singletonFlag = true; } else { throw new RuntimeException("禁止使用反射破坏单例!"); } } } /* //私有化构造函数 private DCLReflectTest() { //在构造器上加约束,避免反射破坏单例 synchronized (DCLReflectTest.class) { if (INSTANCE != null) { throw new RuntimeException("禁止使用反射破坏单例!"); } } }*/ private static volatile DCLReflectTest INSTANCE; public static DCLReflectTest getInstance() { if (INSTANCE == null) { synchronized (DCLReflectTest.class) { if (INSTANCE == null) { INSTANCE = new DCLReflectTest(); } } } return INSTANCE; } public static void main1(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { DCLReflectTest instance1 = DCLReflectTest.getInstance(); //DCL单例模式被反射破坏 Constructor<DCLReflectTest> constructor = DCLReflectTest.class.getDeclaredConstructor(null); constructor.setAccessible(true); DCLReflectTest instance2 = constructor.newInstance(); System.out.println(instance1); System.out.println(instance2); } /** * 输出: * com.lai.springbootdemo.pattern.DCLReflectTest@a09ee92 * com.lai.springbootdemo.pattern.DCLReflectTest@30f39991 */ public static void main2(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { // DCLReflectTest instance1 = DCLReflectTest.getInstance(); //DCL单例模式被反射破坏 Constructor<DCLReflectTest> constructor = DCLReflectTest.class.getDeclaredConstructor(null); constructor.setAccessible(true); //当我们全部使用反射创建单例对象时,前面构造函数对INSTANCE是否为空的判断便没有意义,可以继续不断创建单例对象 DCLReflectTest instance2 = constructor.newInstance(); DCLReflectTest instance3 = constructor.newInstance(); System.out.println(instance3); System.out.println(instance2); } /** * com.lai.springbootdemo.pattern.DCLReflectTest@a09ee92 * com.lai.springbootdemo.pattern.DCLReflectTest@30f39991 */ public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException { // DCLReflectTest instance1 = DCLReflectTest.getInstance(); //DCL单例模式被反射破坏 Constructor<DCLReflectTest> constructor = DCLReflectTest.class.getDeclaredConstructor(null); constructor.setAccessible(true); //当我们全部使用反射创建单例对象时,前面构造函数我们可以设置一个变量或者秘钥控制只有一个线程才能创建成功单例对象 DCLReflectTest instance2 = constructor.newInstance(); //但是当然我们对这个变量继续破坏后又可以破坏了单例模式 //拿到私有域,并设置修改权限为true Field singletonFlag = DCLReflectTest.class.getDeclaredField("singletonFlag"); singletonFlag.setAccessible(true); singletonFlag.set(instance2,false); DCLReflectTest instance3 = constructor.newInstance(); System.out.println(instance3); System.out.println(instance2); } /** * 破坏私有域前: * Caused by: java.lang.RuntimeException: 禁止使用反射破坏单例! * * 破坏私有域后: * com.lai.springbootdemo.pattern.DCLReflectTest@30f39991 * com.lai.springbootdemo.pattern.DCLReflectTest@452b3a41 */ } 枚举单例——不能被反射破坏单例 public class EnumSingletonTest { public static void main(String[] args) throws IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchMethodException { System.out.println(SingleEnum.INSTANCE); // System.out.println(SingleEnum.INSTANCE); //NoSuchMethodException: com.lai.springbootdemo.pattern.SingleEnum.<init>() //枚举类不是无参构造函数,而是SingleEnum(Sting ,int)类型的构造函数,通过jad反编译得知 // Constructor<SingleEnum> constructor = SingleEnum.class.getDeclaredConstructor(null); Constructor<SingleEnum> constructor = SingleEnum.class.getDeclaredConstructor(String.class,int.class); constructor.setAccessible(true); //通过反射创建枚举对象时会被限制:IllegalArgumentException: Cannot reflectively create enum objects constructor.newInstance(); } /** * INSTANCE * INSTANCE */ } enum SingleEnum { INSTANCE; }

Runnable没有返回值,效率与Callable相比较低。原因

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zyxsxy.html