山东枣庄新闻:单例模式,反射破环?

admin/2020-05-30/ 分类:科技/阅读:

饿汉式

// 饿汉式单例 public class Hungry { //组织器私有 private Hungry(){ } // 一上来就把这个类加载了 private final static Hungry HUNGRY = new Hungry(); public static Hungry getInstance(){ return HUNGRY; } } 
// 饿汉式单例 public class Hungry { // 这4组数据异常耗内存资源,饿汉式一上来就把所有的内存内里的器械所有加载进来了,就存在这个空间 // 但这个空间现在是没有使用的,可能会造成虚耗空间 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 getInstance(){ return HUNGRY; } } 

饿汉式单例可能会造成虚耗空间,以是想要用的时刻再去建立这个工具,平时就先放在这个地方,于是就泛起了懒汉式!

懒汉式

// 懒汉式单例 public class LazyMan { // 组织器私有 private LazyMan(){ } private static LazyMan lazyMan; public static LazyMan getInstance(){ if (lazyMan==null){ lazyMan = new LazyMan(); } return lazyMan; } } 

它是有问题的,单线程下确实单例ok,多线程并发就会泛起问题!

测试

// 懒汉式单例 public class LazyMan { // 组织器私有 private LazyMan(){ System.out.println(Thread.currentThread().getName() ":: ok"); } private static LazyMan lazyMan; 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(); } } } 

发现单例有问题,每次效果可能都不一样!

解决

// 懒汉式单例 public class LazyMan { private LazyMan(){ System.out.println(Thread.currentThread().getName() ":: ok"); } private static LazyMan lazyMan; // 双重检测锁模式的 懒汉式单例 DCL懒汉式 public static LazyMan getInstance(){ if (lazyMan==null){ synchronized (LazyMan.class){ 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(); } } } 

但在极端情况下照样可能泛起问题

履历三个步骤:

1、 分配内存空间

2、 执行组织方式,初始化工具

3、 把这个工具指向这个空间

有可能会发生指令重排的操作!

好比,期望它执行 123 ,然则它真实可能执行132,好比第一个A线程过来执行了132,先分配空间再吧这个空间占用了,占用之后再去执行组织方式,若是现在突然来了个B线程,由于A已经指向这个空间了,它会以为这个 lazyMan 不等于 null ,直接return ,此时lazyMan还没有完成组织,所有必须制止这个问题!

必须加上volatile

// 懒汉式单例 public class LazyMan { private LazyMan(){ System.out.println(Thread.currentThread().getName() ":: ok"); } // 制止指令重排 private volatile static LazyMan lazyMan; // 双重检测锁模式的 懒汉式单例 DCL懒汉式 public static LazyMan getInstance(){ if (lazyMan==null){ synchronized (LazyMan.class){ 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(); } } } 

静态内部类

// 静态内部类 public class Holder { private Holder(){ } public static Holder getInstance(){ return InnerClass.HOLDER; } public static class InnerClass{ private static final Holder HOLDER = new Holder(); } } 

也是单例模式的一种,不安全!

单例不安全 反射

// 懒汉式单例 public class LazyMan { private LazyMan(){ System.out.println(Thread.currentThread().getName() ":: ok"); } private volatile static LazyMan lazyMan; // 双重检测锁模式的 懒汉式单例 DCL懒汉式 public static LazyMan getInstance(){ if (lazyMan==null){ synchronized (LazyMan.class){ if (lazyMan==null){ lazyMan = new LazyMan(); //不是一个原子性操作 } } } return lazyMan; } //反射 public static void main(String[] args) throws Exception { LazyMan instance1 = LazyMan.getInstance(); Constructor<LazyMan> declaredConstructor = LazyMan.class.getDeclaredConstructor(null); declaredConstructor.setAccessible(true); // 无视了私有的组织器 // 通过反射建立工具 LazyMan instance2 = declaredConstructor.newInstance(); System.out.println(instance1); System.out.println(instance2); } } 

结论:反射可以损坏这种单例

解决

// 懒汉式单例 public class LazyMan { private LazyMan(){ synchronized (LazyMan.class){ if (lazyMan!=null){ throw new RuntimeException("不要试图使用反射破环 异常"); } } System.out.println(Thread.currentThread().getName() ":: ok"); } private volatile static LazyMan lazyMan; // 双重检测锁模式的 懒汉式单例 DCL懒汉式 public static LazyMan getInstance(){ if (lazyMan==null){ synchronized (LazyMan.class){ if (lazyMan==null){ lazyMan = new LazyMan(); //不是一个原子性操作 } } } return lazyMan; } //反射 public static void main(String[] args) throws Exception { LazyMan instance1 = LazyMan.getInstance(); Constructor<LazyMan> declaredConstructor = LazyMan.class.getDeclaredConstructor(null); declaredConstructor.setAccessible(true); // 无视了私有的组织器 // 通过反射建立工具 LazyMan instance2 = declaredConstructor.newInstance(); System.out.println(instance1); System.out.println(instance2); } } 

然则若是都用反射建立工具的情况下,照样会破环单例!

测试

解决

// 懒汉式单例 public class LazyMan { private static boolean abc = false; private LazyMan(){ synchronized (LazyMan.class){ if (abc==false){ abc=true; }else { throw new RuntimeException("不要试图使用反射破环 异常"); } } System.out.println(Thread.currentThread().getName() ":: ok"); } private volatile static LazyMan lazyMan; // 双重检测锁模式的 懒汉式单例 DCL懒汉式 public static LazyMan getInstance(){ if (lazyMan==null){ synchronized (LazyMan.class){ if (lazyMan==null){ lazyMan = new LazyMan(); //不是一个原子性操作 } } } return lazyMan; } //反射 public static void main(String[] args) throws Exception { //LazyMan instance1 = LazyMan.getInstance(); Constructor<LazyMan> declaredConstructor = LazyMan.class.getDeclaredConstructor(null); declaredConstructor.setAccessible(true); // 无视了私有的组织器 // 通过反射建立工具 LazyMan instance2 = declaredConstructor.newInstance(); LazyMan instance1 = declaredConstructor.newInstance(); System.out.println(instance1); System.out.println(instance2); } } 

然则若是被人知道 abc这个变量,也可以破环!

单例又被破环了!

看一下源码

它说不能使用反射破环枚举,枚举是jdk1.5泛起的,自带单例模式!

测试,写一个枚举类

// enum 自己就是一个class类 public enum EnumSingle { INSTANCE; public EnumSingle getInstance(){ return INSTANCE; } } 

查看它的源码

试图破环!

// enum 自己就是一个class类 public enum EnumSingle { INSTANCE; public EnumSingle getInstance(){ return INSTANCE; } } class Test{ public static void main(String[] args) throws Exception { EnumSingle instance1 = EnumSingle.INSTANCE; Constructor<EnumSingle> declaredConstructor = EnumSingle.class.getDeclaredConstructor(null); declaredConstructor.setAccessible(true); EnumSingle instance2 = declaredConstructor.newInstance(); System.out.println(instance1); System.out.println(instance2); } } 

它竟然说我现在的这个枚举类中没有空参组织器!

然后就去源码里剖析!

找到这个class文件!行使javap反编译一下!

发现这个也显示有一个空参组织,证实这个也纰谬,用第三方的工具查看!

行使它再吧class文件天生java文件!

打开这个java文件

证实是idea和源码骗了我!

再次实验破环!

// enum 自己就是一个class类 public enum EnumSingle { INSTANCE; public EnumSingle getInstance(){ return INSTANCE; } } class Test{ public static void main(String[] args) throws Exception { EnumSingle instance1 = EnumSingle.INSTANCE; Constructor<EnumSingle> declaredConstructor = EnumSingle.class.getDeclaredConstructor(String.class,int.class); declaredConstructor.setAccessible(true); EnumSingle instance2 = declaredConstructor.newInstance(); System.out.println(instance1); System.out.println(instance2); } } 

结论:反射无法破环枚举类!

,

欧博网址

www.goldo.cn欢迎进入欧博网址(Allbet Gaming),欧博网址开放会员注册、代理开户、电脑客户端下载、苹果安卓下载等业务。

TAG:
阅读:
广告 330*360
广告 330*360

热门文章

HOT NEWS
Sunbet_进入申博sunbet官网
微信二维码扫一扫
关注微信公众号
新闻自媒体 Copyright © 2002-2019 Sunbet 版权所有
二维码
意见反馈 二维码