单例模式

Android知识总结

一、饿汉式单例

    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;

        private Person(){
        }

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

懒汉式单例: 可以防止并发时初始化成员变量和对象实例化顺序可能会被打乱,双重校验锁定解决了多余的同步问题。
并发时存在极小的概率导致 DCL 失效,据说是百万分之一。因为指令重排序造成的,所以加volatile来防止指令重排序。

三、静态内部类单例 (推荐)

    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 classType = ElvisModified.class;
 
                Constructor 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();
            }
         }
    }

你可能感兴趣的:(单例模式)