Android单例实现整理 -Java篇

105 阅读2分钟

单例实现方式

懒汉式

基本写法

  • 直接按以下这种方式写是线程不安全
static class Singleton{
    //私有的静态变量
    private static Singleton mInstance = null;
    //私有的构造方法
    private Singleton(){}
    //暴露一个共有静态方法
    public static Singleton getInstance(){
        if(mInstance == null){
            mInstance = new Singleton();
        }
        return mInstance;
    }
}

由于是使用时才创建,多线程环境下可能会有多个线程同时创建 -> 线程不安全

加同步锁

  • 方法上加锁 -可以解决线程不安全问题,但同步锁粒度太大

锁的粒度是指锁定共享资源的范围大小。在多线程环境下,当多个线程访问共享资源时,要确保资源的一致性,避免数据竞争和并发错误。锁的粒度会影响到并发程序的性能

static class Singleton{
    //私有的静态变量
    private static Singleton mInstance = null;
    //私有的构造方法
    private Singleton(){}
    //暴露一个共有静态方法
    public static synchronized Singleton getInstance(){ //同步锁粒度太大
        if(mInstance == null){
            mInstance = new Singleton();
        }
        return mInstance;
    }
}
  • 代码块加锁,volatile关键字

volatile关键字的作用:1.保持对象在内存中的可见性;2.禁止编译器和处理器为优化对指令进行重排序

static class Singleton{
    //私有的静态变量
    private volatile static Singleton mInstance = null;
    //私有的构造方法
    private Singleton(){}
    //暴露一个共有静态方法
    public static Singleton getInstance(){
        if(mInstance == null){
            synchronized(Singleton.class){
                if(mInstance == null){
                    mInstance = new Singleton();
                }
            }
        }
        return mInstance;
    }
}

饿汉式

  • 类加载时就被创建,整个应用程序运行期间只创建这一次,可以确保访问到的始终是这个单例
    • 优点:线程安全
    • 缺点:如果对象较大且未必用得到,会造成资源浪费
static class Singleton{
    private static Singleton sInstance = new Singleton();
    private SingleTon(){}
    public static Singleton getInstance(){
        return sInstance;
    }
}

静态内部类

  • 只有在第一次调用时,单例对象会在静态内部类加载和初始化时被创建
    • 优点:既实现了懒汉式的延迟加载,又实现了饿汉式的线程安全
static class Singleton{
    private Singleton(){}
    
    private static class Holder{
        private static final Singleton INTSTANCE = new Singleton();
    }
    
    public static final Singleton getInstance(){
        return Holder.INSTANCE;
    }
}

枚举类

  • enum类中的每个元素都会且仅会被创建一次
    • 优点:线程安全,实现简单,防止反射和序列化重新创建对象
static enum Singleton{
    INSTANCE;
}

容器管理单例对象

  • 适用于需要管理多个单例实例的场景,可以根据键值对来管理不同的单例对象

Android中如获取NotificationManager应该就是采用这种方式

static class SingletonManager{
    private static Map<String,Object> objMap = new HashMap<>();
    
    public static void registerService(String key,Object instance){
        if(!objMap.containsKey(key)){
            objMap.put(key,instance);
        }
    }

    public static Object getService(String key){
            return objMap.get(key);
    }
}

这里的总结或多或少有考虑不周之处,欢迎补充和指正!!!