安卓开发笔记 之 单例

发布于 2024-10-28 10:13:30 字数 3076 浏览 19 评论 0

Double Check

  public class Singleton {
    private static volatile Singleton singleton = null;
    private Singleton() {
    }

    public static Singleton getSingleton() {
      if (singleton == null) { // 尽量避免重复进入同步块
        synchronized (Singleton.class) { // 同步 .class,意味着对同步类方法调用
          if (singleton == null) {
            singleton = new Singleton();
          }
        }
      }
      return singleton;
    }
  }
  • 如果两个线程竞争同一把锁,无非是排队执行还是会初始化两次,因此里面再加一次为空判断
  • 为什么用 volatile? 原理
    • 保证内存可见性
    • 禁止指令重排序(happens-before 原则)
    • 在 JVM 底层 volatile 是采用 内存屏障 来实现的

这里一定注意: volatile 关键字, 为什么必须要有

  • 使用静态内部类
public class Singleton {
  private Singleton(){}
  public static Singleton getSingleton(){
    return Holder.singleton;
  }
  
  private static class Holder {
    private static Singleton singleton = new Singleton();
  }
}
  • 利用了静态对象初始化过程中隐含的初始化锁,和 Double Check 异曲同工。
  • 静态内部类的优点是:外部类加载时并不需要立即加载内部类,内部类不被加载则不去初始化 INSTANCE,故而不占内存
  • 通过反射,是不能从外部类获取内部类的属性的。内部类是 static 的,上面的 this$0 是有限制的,静态内部类和静态方法里面的内部类是没有 this$0 这个引用的,因为静态内部类,是面向类的而不是对象,能够独自的应用本身,而脱离外部类,和外部类没有这个引用关系。
  • 虚拟机会保证一个类的 <clinit>() 方法在多线程环境中被正确地加锁、同步,如果多个线程同时去初始化一个类,那么只会有一个线程去执行这个类的 <clinit>() 方法,其他线程都需要阻塞等待,直到活动线程执行 <clinit>() 方法完毕。 详见类加载部分
  • 分析
  • 缺点
    • 不能传参
    • 一旦销毁就不能重新创建

Android 中的使用

context.getSystemService,跨进程与系统服务通信

Context 的两个子类分工明确,其中 ContextImpl 是 Context 的具体实现类,ContextWrapper 是 Context 的包装类。Activity, Application,Service 虽都继承自 ContextWrapper(Activity 继承自 ContextWrapper 的子类 ContextThemeWrapper),但它们初始 化的过程中都会创建 ContextImpl 对象,由 ContextImpl 实现 Context 中的方法。

// 系统服务容器
private static final HashMap<String, ServiceFetcher> SYSTEM_SERVICE_MAP = new HashMap<String, ServiceFetcher>();

// 注册服务
private static void registerService(String serviceName, ServiceFetcher fetcher) {
  if (!(fetcher instanceof StaticServiceFetcher)) {
    fetcher.mContextCacheIndex = sNextPerContextServiceCacheIndex++;
  }
  SYSTEM_SERVICE_MAP.put(serviceName, fetcher);
}
  
// 根据 key 获取对应的服务
@Override
public Object getSystemService(String name) {
  ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name);
  return fetcher == null ? null : fetcher.getService(this);
}  

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

0 文章
0 评论
666 人气
更多

推荐作者

隔纱相望

文章 0 评论 0

昵称有卵用

文章 0 评论 0

梨涡

文章 0 评论 0

蓝咒

文章 0 评论 0

白芷

文章 0 评论 0

樱娆

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文