深入解析Android中的CAS与synchronized并发控制:LifecycleScope与ViewModelScope源码分析

admin2024-06-11  11

前言

Android平台上,并发编程对于确保应用的响应性和用户体验至关重要。Kotlin协程库提供的lifecycleScopeviewModelScope是开发者常用的两个关键工具,它们分别通过CAS(Compare-And-Swap)和synchronized机制确保线程安全和协程的生命周期管理。本文将首先介绍CAS和synchronized两种并发控制机制,然后探讨它们在Android源码中的具体实现。

并发控制中的乐观锁与悲观锁

并发控制机制可以从不同角度进行分类,其中乐观锁和悲观锁是常见的两种方式。

乐观锁

乐观锁总是假设对共享资源的访问没有冲突,线程可以不停地执行,无需加锁也无需等待。一旦多个线程发生冲突,乐观锁通常使用一种称为CAS(Compare-And-Swap)的技术来保证线程执行的安全性。由于乐观锁假设操作中没有锁的存在,因此不太可能出现死锁,换句话说,乐观锁天生免疫死锁。乐观锁多用于“读多写少”的环境,避免频繁加锁影响性能;而悲观锁多用于“写多读少”的环境,避免频繁失败和重试影响性能。

悲观锁

悲观锁总是假设每次访问共享资源时会发生冲突,所以必须对每次数据操作加上锁,以保证临界区的程序同一时间只能有一个线程在执行。这种方式确保了数据的一致性,但也增加了性能开销,特别是在写操作频繁的场景中。synchronized关键字在Java中就是一种悲观锁的实现。

CAS (Compare-And-Swap) 机制

CAS(Compare-and-Swap)是一种被广泛应用在并发控制中的算法,它是一种乐观锁的实现方式,通过比较内存中的值与预期值,如果一致则更新为新值,否则重试。CAS操作的步骤如下:

  1. V:当前值。
  2. E:预期值(旧值)。
  3. N:新值。
CAS的工作原理

比较并交换的过程如下:

  1. 判断 V 是否等于 E。如果相等,将 V 的值设置为 N。
  2. 如果不相等,说明已经有其它线程更新了 V,于是当前线程放弃更新,什么都不做。

CAS操作的核心是保证这一过程的原子性,确保在多线程环境中只有一个线程能够成功更新变量,其余线程则重试或放弃。

示例

假设有一个共享变量 i,初始值为 9。线程 A 尝试将其更新为 10:

  1. 线程 A 检查 i 是否为 9(E)。
  2. 如果 i 仍为 9,则将其更新为 10(N)。
  3. 如果 i 不是 9,说明其他线程已经修改过 i,此操作失败。

由于 CAS 是原子操作,底层通过CPU指令(如X86架构的cmpxchgl指令)保证其原子性。即使在多处理器环境中,也能通过lock指令确保操作的完整性。

CAS在Java中的实现

在 Java 中,CAS 操作由Unsafe类提供,该类包含一些本地方法,通过 JVM 使用 C 或 C++ 实现。

以下是Unsafe类中一些关于CAS的方法:

boolean compareAndSwapObject(Object o, long offset, Object expected, Object x);
boolean compareAndSwapInt(Object o, long offset, int expected, int x);
boolean compareAndSwapLong(Object o, long offset, long expected, long x);

这些方法底层通过不同平台的特定指令实现原子操作。例如,Linux 的 X86 架构下,CAS 操作由cmpxchgl指令完成。 Java 9 引入了 VarHandler类,这是Java 内存模型的一项重大改进,它提供了一种更灵活更高效的方式替代Unsafe。使得其更加安全和易用。

CAS 的优缺点

优点:

  • 高性能:避免了锁的开销,适合高并发读操作的场景。
  • 无阻塞:线程无需等待锁释放,可以直接重试,提高了系统的吞吐量。

缺点:

  • ABA问题:值可能被其他线程修改再恢复原值,导致错误判断。可以通过版本号或时间戳解决。
  • 复杂性:实现复杂,难以调试和维护。

synchronized机制

Synchronized是Java提供的关键字,用于在多个线程之间实现同步。它通过内置锁保证在同一时间只有一个线程可以访问被同步的代码块,确保线程安全。

synchronized的优缺点

优点:

  • 简单易用:语法简单,易于理解和使用。
  • 严格顺序:保证操作的严格顺序,适合需要顺序执行的场景。

缺点:

  • 性能开销:频繁的锁竞争会带来较大的性能开销,可能导致线程阻塞。
  • 死锁风险:不当使用可能会导致死锁,影响系统稳定性。

LifecycleScope的CAS实现

在Android的lifecycleScope实现中,利用了CAS机制来确保线程安全。以下是Lifecycle.coroutineScope属性的实现代码:

public val Lifecycle.coroutineScope: LifecycleCoroutineScope
    get() {
        while (true) {
            val existing = mInternalScopeRef.get() as LifecycleCoroutineScopeImpl?
            if (existing != null) {
                return existing
            }
            val newScope = LifecycleCoroutineScopeImpl(
                this,
                SupervisorJob() + Dispatchers.Main.immediate
            )
            if (mInternalScopeRef.compareAndSet(null, newScope)) {
                newScope.register()
                return newScope
            }
        }
    }

这段代码通过不断尝试更新原子引用,确保只创建一个LifecycleCoroutineScope实例,体现了CAS机制的乐观锁策略。

ViewModelScope的synchronized实现

相对于Lifecycle.coroutineScope的CAS实现,ViewModel.viewModelScope采用了Synchronized机制来保证线程安全。以下是ViewModel.viewModelScope属性及其辅助函数setTagIfAbsent的实现代码:

public val ViewModel.viewModelScope: CoroutineScope
    get() {
        val scope: CoroutineScope? = this.getTag(JOB_KEY)
        if (scope != null) {
            return scope
        }
        return setTagIfAbsent(
            JOB_KEY,
            CloseableCoroutineScope(SupervisorJob() + Dispatchers.Main.immediate)
        )
    }

private fun <T> setTagIfAbsent(key: String, newValue: T): T {
    synchronized(mBagOfTags) {
        val previous = mBagOfTags.get(key) as T?
        if (previous == null) {
            mBagOfTags.put(key, newValue)
        }
        return previous ?: newValue
    }
}

这段代码使用了synchronized关键字来保护对mBagOfTags映射的访问,确保在多个线程尝试更新同一个ViewModel的viewModelScope时,只有一个能够成功。

并发控制优化策略

在实际应用中,正确选择并发控制策略对于性能和稳定性至关重要。CAS提供了无锁的解决方案,适用于并发写操作较少的场景;而synchronized则适用于写操作较频繁或需要保证操作顺序的场景。开发者在实现特定功能时需要考虑如何平衡这两种策略的利弊,以实现最佳性能和可靠性。

结论

lifecycleScopeviewModelScope在Android并发编程中提供了有效的线程同步机制。通过深入理解它们的实现,开发者可以更好地管理协程的生命周期,编写既安全又高效的并发代码。

最后

如果想要成为架构师或想突破20~30K薪资范畴,那就不要局限在编码,业务,要会选型、扩展,提升编程思维。此外,良好的职业规划也很重要,学习的习惯很重要,但是最重要的还是要能持之以恒,任何不能坚持落实的计划都是空谈。

如果你没有方向,这里给大家分享一套由阿里高级架构师编写的《Android八大模块进阶笔记》,帮大家将杂乱、零散、碎片化的知识进行体系化的整理,让大家系统而高效地掌握Android开发的各个知识点。

深入解析Android中的CAS与synchronized并发控制:LifecycleScope与ViewModelScope源码分析,深入解析Android中的CAS与synchronized并发控制:LifecycleScope与ViewModelScope源码分析_Java,第1张


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明原文出处。如若内容造成侵权/违法违规/事实不符,请联系SD编程学习网:675289112@qq.com进行投诉反馈,一经查实,立即删除!