Android 设计模式-单例模式

2020-06-10  本文已影响0人  涛涛123759

饿汉式单例

public class Person {

    private static final Person INSTANCE = new Person();

    private Person(){
    }

    public static Person getInstance() {
      return INSTANCE;
    }
}

优点:线程安全。
缺点:类加载的时候就进行初始化,对于初始化逻辑复杂的类,会导致类加载变慢。

** 懒汉式单例**

public class Person {
    private static volatile Person sInstance = new Person();

    private Person(){
    }

    public static Person getInstance() {
        if (sInstance == null){
            synchronized (Person.class) {
                if (sInstance == null) {
                    sInstance = new Person();
                }
            }
        }
        return sInstance;
    }
}

优点:volatile 声明单例引用,可以防止并发时初始化成员变量和对象实例化顺序可能会被打乱,双重校验锁定解决了多余的同步问题。
缺点:并发时存在极小的概率导致 DCL 失效,据说是百万分之一。

静态内部类单例 (推荐)

public class Person {

    private Person(){
    }

    private static class Singleton {
        private static final Person INSTANCE = new Person();
    }

    public static Person getInstance() {
        return Singleton.INSTANCE;
    }
}

优点:充分结合了懒汉式单例与饿汉式的优点,同时有效避开了它们的缺点,充分保证线程安全。推荐
缺点:会有的!

枚举型单例

public enum PersonEnum {
    INSTANCE;

    private PersonEnum() {
    }

    public void fun() {
        // do something
    }
}

使用方法:

PersonEnum.INSTANCE.fun();

优点:简洁,线程安全。
缺点:Google 官方强烈建议尽量不要使用 enum ,它会增加额外的内存占用,同时增加可执行文件 .dex 的大小,也不适用继承场景。

———————————————————————————————————————————

如何防止单例模式被JAVA反射攻击

如果要抵御这种攻击,可以修改构造器,让它在被要求创建第二个实例的时候抛出异常。

package com.effective.singleton;

public class ElvisModified{
    private static boolean flag = false;

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

    private  static class SingletonHolder{
        private static final ElvisModified INSTANCE = new ElvisModified();
    }

    public static ElvisModified getInstance() {
        return SingletonHolder.INSTANCE;
    }

    public void doSomethingElse(){

    }
}

测试代码:

public class ElvisModifiedReflectAttack{

    public static void main(String[] args) {
        try  {
            Class<ElvisModified> classType = ElvisModified.class;

            Constructor<ElvisModified> c = classType.getDeclaredConstructor(null);
            c.setAccessible(true);
            ElvisModified e1 = (ElvisModified)c.newInstance();
            ElvisModified e2 = ElvisModified.getInstance();
            System.out.println(e1==e2);
        } catch (Exception e) {
            e.printStackTrace();
        }
     }
}
上一篇 下一篇

猜你喜欢

热点阅读