Android 单例模式的正确姿势

简介:

单例模式是使用得最多的设计模式,模版代码也很多。但是如果使用不当还是容易出问题。

DCL模式(双重检查锁定模式)的正确使用方式

一般我们使用DCL方法来实现单例模式时都是这样的模版代码:

private static Singleton mSingleton = null;
private Singleton () {}

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

}
AI 代码解读

实际上,上述方法在多线程的环境下,还是会有可能创建多个实例。为什么呢?

mConstant = new Constant()这行代码虚拟机在执行的时候会有多个操作,大致包括:

  • 为新的对象分配内存
  • 调用Constant的构造方法,初始化成员变量
  • 将mConstant这个引用指向新创建的Constant对象的地址

在多线程环境下,每个线程的私有内存空间中都有mSingleton的副本。这导致可能存在下面的情况:

  • 当在一个线程中初始化mSingleton后,主内存中的mSingleton变量的值可能并没有及时更新;
  • 主内存的mSingleton变量已经更新了,但在另一个线程中的mSingleton变量没有即时从主内存中读取最新的值

这样的话就有可能创建多个实例,虽然这种几率比较小。

那怎么解决这个问题呢?答案是使用volatile关键字

volatile关键字能够保证可见性,被volatile修饰的变量,在一个线程中被改变时会立刻同步到主内存中,而另一个线程在操作这个变量时都会先从主内存更新这个变量的值。

更保险的单例模式实现

private volatile static Singleton mSingleton = null;
private Singleton () {}

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

}
AI 代码解读

使用单例模式,小心内存泄漏了喔~

单例模式的静态特性导致它的对象的生命周期是和应用一样的,如果不注意这一点就可能导致内存泄漏。下面看看常见的2种情况

  • Context的泄漏
//SingleInstance.class
private volatile static SingleInstance mSingleInstance = null;
private SingleInstance (Context context) {}

public static SingleInstance getInstance(Context context) {
    if (mSingleInstance == null) {
        synchronized (SingleInstance.class) {
            if (mSingleInstance == null) {
                mSingleInstance = new SingleInstance(context);
            }
        }
    }
    return mSingleInstance;

}

//MyActivity
public class MyActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        //这样就容易出问题了
        SingleInstance singleInstance = SingleInstance.getInstance(this);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
    }
}
AI 代码解读

如上面那样直接传入MyActivity的引用,如果当前MyActivity退出了,但应用还没有退出,singleInstance一直持有MyActivity的引用,MyActivity就不能被回收了。

解决方法也很简单,传入ApplicationContext就可以了。

SingleInstance singleInstance = SingleInstance.getInstance(getApplicationContext());
AI 代码解读
  • View的泄漏

如果单例模式的类中有跟View相关的属性,就需要注意了。搞不好也会导致内存泄漏,原因和上面分析的原因一样。

//SingleInstance.class
private volatile static SingleInstance mSingleInstance = null;
private SingleInstance (Context context) {}

public static SingleInstance getInstance(Context context) {
    if (mSingleInstance == null) {
        synchronized (SingleInstance.class) {
            if (mSingleInstance == null) {
                mSingleInstance = new SingleInstance(context);
            }
        }
    }
    return mSingleInstance;

}

//单例模式中这样持有View的引用会导致内存泄漏
private View myView = null;
public void setMyView(View myView) {
    this.myView = myView;
}
AI 代码解读

解决方案是采用弱引用

private volatile static SingleInstance mSingleInstance = null;
private SingleInstance (Context context) {}

public static SingleInstance getInstance(Context context) {
    if (mSingleInstance == null) {
        synchronized (SingleInstance.class) {
            if (mSingleInstance == null) {
                mSingleInstance = new SingleInstance(context);
            }
        }
    }
    return mSingleInstance;

}

//    private View myView = null;
//    public void setMyView(View myView) {
//        this.myView = myView;
//    }

//用弱引用
private WeakReference<View> myView = null;
public void setMyView(View myView) {
    this.myView = new WeakReference<View>(myView);
}
AI 代码解读

很多东西虽然简单,还是有我们需要注意的地方。这就需要我们理解它们的特性了。比如上面用了弱引用来解决内存泄漏的问题,那我们就需要明白弱引用的特点,需要注意使用弱引用的变量可能为空的问题

被弱引用关联的对象只能生存到下一次垃圾收集发生之前,当垃圾收集器工作时,无论当前内存是否足够,都会回收掉只被弱引用关联的对象


今天你进步了嘛?欢迎关注我的微信公众号,和我一起每天进步一点点!
AntDream

目录
相关文章
Android 单例模式必知必会
一、概念 单例模式是运用最广泛的设计模式之一,在应用这个模式时,单例模式的类必须保证只有一个实例存在。多用于整个程序只需要有一个实例,通常很消耗资源的类,比如线程池,缓存,网络请求,IO操作,访问数据库等。由于类比较耗资源,所以没必要让它构造多个实例,这种就是单例模式比较好的使用场景。
233 0
我要做 Android 之单例模式
Q:实现单例模式有几种方法?懒汉式中双层锁的目的是什么?两次判空的目的又是什么? 懒汉式(线程不安全) 单例模式最后的目的无非就是获取当前存在的实例对象,如果没有实例对象就实例化一个,有就直接返回。
1217 0
Android--单例模式
版权声明:本文为博主原创文章,转载请标明出处。 https://blog.csdn.net/chaoyu168/article/details/78897883 ###定义 保证一个类仅有一个实例,并提供一个访问它的全局访问点。
856 0
Android设计模式系列-单例模式
版权声明:本文为博主原创文章,转载请标明出处。 https://blog.csdn.net/chaoyu168/article/details/52592563 单例模式,可以说是GOF的23种设计模式中最简单的一个。
944 0
Android设计模式系列(3)--SDK源码之单例模式
原文链接:http://www.cnblogs.com/qianxudetianxia/archive/2011/08/07/2130306.html 单例模式,可以说是GOF的23种设计模式中最简单的一个。
1014 0
【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
42 8
【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
171 20
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
54 4
【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
【04】flutter补打包流程的签名过程-APP安卓调试配置-结构化项目目录-完善注册相关页面-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程
【04】flutter补打包流程的签名过程-APP安卓调试配置-结构化项目目录-完善注册相关页面-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程
103 12
【04】flutter补打包流程的签名过程-APP安卓调试配置-结构化项目目录-完善注册相关页面-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程
escrcpy:【技术党必看】Android开发,Escrcpy 让你无线投屏新体验!图形界面掌控 Android,30-120fps 超流畅!🔥
escrcpy 是一款基于 Scrcpy 的开源项目,使用 Electron 构建,提供图形化界面来显示和控制 Android 设备。它支持 USB 和 Wi-Fi 连接,帧率可达 30-120fps,延迟低至 35-70ms,启动迅速且画质清晰。escrcpy 拥有丰富的功能,包括自动化任务、多设备管理、反向网络共享、批量操作等,无需注册账号或广告干扰。适用于游戏直播、办公协作和教育演示等多种场景,是一款轻量级、高性能的 Android 控制工具。

热门文章

最新文章

  • 1
    Android历史版本与APK文件结构
    15
  • 2
    【01】噩梦终结flutter配安卓android鸿蒙harmonyOS 以及next调试环境配鸿蒙和ios真机调试环境-flutter项目安卓环境配置-gradle-agp-ndkVersion模拟器运行真机测试环境-本地环境搭建-如何快速搭建android本地运行环境-优雅草卓伊凡-很多人在这步就被难倒了
    18
  • 3
    APP-国内主流安卓商店-应用市场-鸿蒙商店上架之必备前提·全国公安安全信息评估报告如何申请-需要安全评估报告的资料是哪些-优雅草卓伊凡全程操作
    15
  • 4
    【03】仿站技术之python技术,看完学会再也不用去购买收费工具了-修改整体页面做好安卓下载发给客户-并且开始提交网站公安备案-作为APP下载落地页文娱产品一定要备案-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
    4
  • 5
    【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
    2
  • 6
    Cellebrite UFED 4PC 7.71 (Windows) - Android 和 iOS 移动设备取证软件
    7
  • 7
    escrcpy:【技术党必看】Android开发,Escrcpy 让你无线投屏新体验!图形界面掌控 Android,30-120fps 超流畅!🔥
    4
  • 8
    【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
    2
  • 9
    即时通讯安全篇(一):正确地理解和使用Android端加密算法
    12
  • 10
    Android实战经验之Kotlin中快速实现MVI架构
    9
  • 1
    android FragmentManager 删除所有Fragment 重建
    18
  • 2
    Android实战经验之Kotlin中快速实现MVI架构
    31
  • 3
    即时通讯安全篇(一):正确地理解和使用Android端加密算法
    36
  • 4
    escrcpy:【技术党必看】Android开发,Escrcpy 让你无线投屏新体验!图形界面掌控 Android,30-120fps 超流畅!🔥
    43
  • 5
    【01】噩梦终结flutter配安卓android鸿蒙harmonyOS 以及next调试环境配鸿蒙和ios真机调试环境-flutter项目安卓环境配置-gradle-agp-ndkVersion模拟器运行真机测试环境-本地环境搭建-如何快速搭建android本地运行环境-优雅草卓伊凡-很多人在这步就被难倒了
    147
  • 6
    Cellebrite UFED 4PC 7.71 (Windows) - Android 和 iOS 移动设备取证软件
    47
  • 7
    【03】仿站技术之python技术,看完学会再也不用去购买收费工具了-修改整体页面做好安卓下载发给客户-并且开始提交网站公安备案-作为APP下载落地页文娱产品一定要备案-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
    59
  • 8
    Android历史版本与APK文件结构
    164
  • 9
    【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
    48
  • 10
    【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
    42
  • AI助理

    你好,我是AI助理

    可以解答问题、推荐解决方案等