如何破坏单例模式?如何防止?

单例模式的书写

这里列出懒汉式的写法

/**在多线程下如何保证单例模式需要记住三点。
  *第一就是双重加锁机制。
  *第二是确保SingleTest为volatile变量。
  *第三,是我觉得最容易被遗忘的一点,就是构造函数为private。
*/
public class SingleTest {

    public static volatile SingleTest singleTest ;

    private SingleTest(){
    }

    public static SingleTest getSingleTest(){
        if(singleTest==null){
            synchronized(SingleTest.class){
                if(singleTest==null){
                    singleTest = new SingleTest();
                }
            }
        }
        return singleTest;
    }
}

单例模式的破坏

上面的写法看起来没问题,但是存在安全问题。因为我们可以通过反射破坏单例模式。

public static void main(String[] args) throws Exception{

        Constructor constructor = SingleTest.class.getDeclaredConstructor();
        constructor.setAccessible(true);

        SingleTest s1 = SingleTest.getSingleTest();
        SingleTest s2 = SingleTest.getSingleTest();
        SingleTest s3 = (SingleTest) constructor.newInstance();

        System.out.println("输出结果为:"+s1.hashCode()+"," +s2.hashCode()+","+s3.hashCode());
}
输出结果为:1286131032,1286131032,1581347769

从输出的结果我们就可以看出s1和s2为同一对象,s3为新对象。s3是我们通过反射机制,进而调用了私有的构造函数,然后产生了一个新的对象。

诶,既然单例模式存在漏洞,在JDK中那些应用单例模式的对象不是就会被恶意破坏了嘛。当时我也这样想的,我尝试了一下去破坏Runtime(在JDK为单例模式对象)。

public static void main(String[] args) throws Exception{

    Constructor constructor1 = Runtime.class.getConstructor();
    Runtime r1 = (Runtime) constructor1.newInstance();
    Runtime r2 = Runtime.getRuntime();
    Runtime r3 = Runtime.getRuntime();

    System.out.println(r1.hashCode());
    System.out.println(r2.hashCode());
    System.out.println(r3.hashCode());
}

结果是被异常抛出,查看源码就看得出,JDK对已经封装好的单例对象是有保护机制的。

防止单例模式的破坏

那么我们如何去保护我们自定义的单例对象呢?很简单,只需要修私有的构造函数即可。

private static boolean flag = false;

private SingleTest(){
        synchronized(SingleTest.class){
            if(flag == false){
                flag = !flag;
            }else {
                throw new RuntimeException("单例模式被侵犯!");
            }
        }
 }

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/MakeContral/article/details/78713458

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值