单例模式
饿汉式
package com.sw.single;
/**
* @Author suaxi
* @Date 2021/2/21 18:57
* 饿汉式单例
*/
public class Hungry {
private byte[] data1 = new byte[1024 * 1024];
private byte[] data2 = new byte[1024 * 1024];
private byte[] data3 = new byte[1024 * 1024];
private byte[] data4 = new byte[1024 * 1024];
private Hungry(){
}
private final static Hungry hungry = new Hungry();
public static Hungry getHungry() {
return hungry;
}
}
懒汉式
package com.sw.single;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
/**
* @Author suaxi
* @Date 2021/2/21 18:59
* 懒汉式单例
*/
public class Lazy {
//通过私有参数保证单例模式的安全
private static boolean flag = false;
private Lazy() {
synchronized (Lazy.class){
if (flag == false){
flag = true;
}else {
throw new RuntimeException("不要试图使用反射破环单例模式");
}
}
System.out.println(Thread.currentThread().getName() + " ok");
}
private volatile static Lazy lazy;
//双重检测锁模式的 懒汉式单例 DCL懒汉式
public static Lazy getInstance(){
if (lazy == null){
synchronized (Lazy.class){
if (lazy == null){
lazy = new Lazy(); //不是一个原子性操作
/*
不是一个原子性操作,可能存在问题
new 对象的过程:
1、分配内存空间
2、执行构造方法。初始化对象
3、把对象指向这个空间
一般来说的执行过程 123
132 A 可能出现指令重排
B B线程执行时,由于A线程中的指令重排导致的问题,此时Lazy还没有完成构造
解决办法:volatile
*/
}
}
}
return lazy;
}
//多线程并发
// public static void main(String[] args) {
// for (int i = 0; i < 10; i++) {
// new Thread(() ->{
// Lazy.getInstance();
// }).start();
// }
// }
//反射 可以破环单例模式
public static void main(String[] args) throws Exception {
//Lazy instance01 = Lazy.getInstance(); //第一次
//第三次,通过反射获取私有字段flag
Field flag = Lazy.class.getDeclaredField("flag");
flag.setAccessible(true);
Constructor<Lazy> declaredConstructor = Lazy.class.getDeclaredConstructor(null);
declaredConstructor.setAccessible(true); //无视私有构造
//第二次,两个对象都通过以下方式构造,又破坏了三重检测锁的单例模式
Lazy instance01 = declaredConstructor.newInstance();
flag.set(instance01,false); //此处又破坏了
Lazy instance02 = declaredConstructor.newInstance();
System.out.println(instance01); //com.sw.single.Lazy@74a14482
System.out.println(instance02); //com.sw.single.Lazy@1540e19d
}
/*
1、第一次破环单例模式,通过反射创建instance对象
2、加上三重检测锁,又通过全部使用反射创建对象来破坏(第二次)
3、设置私有变量 flag,通过反射获取私有变量字段,又破坏了单例
*/
}
静态内部类
package com.sw.single;
/**
* @Author suaxi
* @Date 2021/2/21 19:48
* 静态内部类
*/
public class Holder {
private Holder(){
}
public static Holder getInstance(){
return InnerClass.holder;
}
public static class InnerClass{
private static final Holder holder = new Holder();
}
}
枚举
package com.sw.single;
import java.lang.reflect.Constructor;
/**
* @Author suaxi
* @Date 2021/2/21 20:10
*/
public enum EnumSingle {
INSTANCE;
public EnumSingle getInstance(){
return INSTANCE;
}
}
class Test{
public static void main(String[] args) throws Exception {
EnumSingle instance01 = EnumSingle.INSTANCE;
Constructor<EnumSingle> declaredConstructor = EnumSingle.class.getDeclaredConstructor(String.class,int.class);
declaredConstructor.setAccessible(true);
EnumSingle instance02 = declaredConstructor.newInstance();
//获取空参的反射报错 没有无参构造器
// java.lang.NoSuchMethodException: com.sw.single.EnumSingle.<init>()
//EnumSingle.class.getDeclaredConstructor(String.class,int.class);
//报错 java.lang.IllegalArgumentException: Cannot reflectively create enum objects
//反射不能破坏枚举
System.out.println(instance01 == instance02);
}
}
注:需通过jad反编译,EnumSingle.class.getDeclaredConstructor(String.class,int.class);
反射获取有参构造才能得出java.lang.IllegalArgumentException: Cannot reflectively create enum objects
(反射不能破坏枚举),常规的通过反射获取无参构造只会报错java.lang.NoSuchMethodException
评论 (0)