反射破坏单例模式及解决办法

使用反射对单例模式的破坏:

/**
 * 反射破坏单例
 */
public class ProxyBreakSingleton {
    @Test
    public void test(){
        //通过单例模式创建对象
        DoubleIfSynchronizedSingleton synchronizedSingleton = DoubleIfSynchronizedSingleton.getSingleton();
        //反射创建对象
        DoubleIfSynchronizedSingleton proxySingleton = ProxyBreakSingleton.getProxySingleton();

        System.out.println("hashCode of synchronizedSingleton:"+synchronizedSingleton.hashCode());
        System.out.println("hashCode of proxySingleton:"+proxySingleton.hashCode());
        System.out.println(synchronizedSingleton == proxySingleton);
    }

    /**
     * 反射获取单例模式对象
     */
    private static DoubleIfSynchronizedSingleton getProxySingleton(){
        DoubleIfSynchronizedSingleton newSingleton = null;
        Constructor<DoubleIfSynchronizedSingleton> constructor = null;
        try {
            constructor = DoubleIfSynchronizedSingleton.class.getDeclaredConstructor();
            constructor.setAccessible(true);
            newSingleton = constructor.newInstance();
        } catch (NoSuchMethodException | IllegalAccessException | InstantiationException | InvocationTargetException e) {
            e.printStackTrace();
        }
        return newSingleton;
    }
}

/**
 * 双重检测锁的单例模式
 */
class DoubleIfSynchronizedSingleton{
    private volatile static DoubleIfSynchronizedSingleton singleton = null;
    private DoubleIfSynchronizedSingleton(){}
    public static DoubleIfSynchronizedSingleton getSingleton(){
        if (singleton == null){
            synchronized (DoubleIfSynchronizedSingleton.class){
                if (singleton == null){
                    singleton = new DoubleIfSynchronizedSingleton();
                }
            }
        }
        return singleton;
    }
}

执行结果:

hashCode of synchronizedSingleton:1642360923
hashCode of proxySingleton:1343441044
false

hashCode和对象地址都不同,可以看出是两个对象,破坏了单例模式。

解决办法:

在双重检测锁单例模式的构造器中使用计数的方式确保只生产一个对象,因为反射也是调用构造器创建对象。

/**
 * 双重检测锁的单例模式
 */
class DoubleIfSynchronizedSingleton {
    private static int count = 0;
    private volatile static DoubleIfSynchronizedSingleton singleton = null;

    private DoubleIfSynchronizedSingleton() {
        synchronized (DoubleIfSynchronizedSingleton.class) {
            if (count > 0){
                throw new RuntimeException("你居然敢破坏我的单例.....");
            }
            count++;
        }
    }

    public static DoubleIfSynchronizedSingleton getSingleton() {
        if (singleton == null) {
            synchronized (DoubleIfSynchronizedSingleton.class) {
                if (singleton == null) {
                    singleton = new DoubleIfSynchronizedSingleton();
                }
            }
        }
        return singleton;
    }
}

修改之后的执行结果:

java.lang.reflect.InvocationTargetException
	......
Caused by: java.lang.RuntimeException: 你居然敢破坏我的单例.....
	......

执行结果抛出异常。


版权声明:本文为llangzh原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。