6-11.【多线程】ArkTS 是否支持共享内存?是否支持线程间锁?

4 阅读2分钟

1. ArkTS 是否支持共享内存?

结论:支持,但分为“数据块共享”和“对象级共享”两种模式。

传统的 ArkTS 线程(Actor 模型)是内存隔离的,但为了性能,系统提供了以下两种途径实现内存共享:

A. SharedArrayBuffer(字节级共享)

这是最基础的共享方式,允许两个或多个线程同时映射同一块物理内存。

  • 原理:它是一块原始的二进制缓冲区。线程 A 写入,线程 B 可以立即读取。
  • 局限性:只能存储基础数值类型,不支持直接存取 ArkTS 对象(如 class 实例)。需要配合 Atomics(原子操作)来防止读写冲突。

B. Sendable 对象(对象级共享 - 核心特性)

这是 HarmonyOS NEXT 引入的重量级特性。标记为 @Sendable 的类在跨线程传递时,不再进行“序列化-拷贝”,而是直接引用传递

  • 原理:多个线程指向堆内存中的同一个对象实例。
  • 要求:Sendable 类有严格限制,例如属性必须也是 Sendable 类型或基础类型,且不支持在运行时动态添加属性。

2. 是否支持线程间锁?

结论:支持,但为了不阻塞 UI 线程,ArkTS 采用了“异步锁(AsyncLock)”机制。

在支持了共享内存(尤其是 Sendable 对象)后,必然会出现多个线程同时修改同一个对象的情况。为此,系统提供了 libuv 深度集成的异步锁。

A. 异步锁(@ohos.utils.ArkTSUtils.locks)

与 C++/Java 中的阻塞锁(如 synchronized)不同,ArkTS 的锁是非阻塞的:

  • 执行方式:当线程尝试获取锁时,如果锁已被占用,它会返回一个 Promise 并在队列中等待,而不会卡死当前线程(这对 UI 线程至关重要)。

  • 代码示例

    TypeScript

    import { ArkTSUtils } from '@kit.ArkTS';
    let lock = new ArkTSUtils.locks.AsyncLock();
    
    async function updateSharedData() {
      // 异步获取锁,并在回调执行完后自动释放
      await lock.lockAsync(() => {
        // 在这里安全地操作 Sendable 共享对象
        sharedObject.count++;
      });
    }
    

B. 原子操作(Atomics)

针对 SharedArrayBuffer,系统支持标准 JavaScript 的 Atomics 接口。

  • 它提供指令级的锁(如 Atomics.waitAtomics.notify),适用于底层的数值同步,但不建议在 UI 线程使用 Atomics.wait,因为它会物理阻塞线程。

3. 共享与锁的选择维度

需求场景推荐方案性能损耗
传递少量配置信息普通对象(序列化拷贝)高(随数据量增大)
大数据块(如像素数据)SharedArrayBuffer极低(零拷贝)
复杂业务模型共享@Sendable 对象极低(引用传递)
多线程竞争修改数据AsyncLock低(异步排队,无阻塞)

架构师总结

ArkTS 的设计理念是 “能隔离就隔离,必须共享则加锁”

  1. UI 安全优先:即便有了共享内存,也不建议在主线程频繁加锁。
  2. 避免死锁:由于 AsyncLock 是异步的,它能有效避免传统多线程开发中常见的循环等待导致的死锁(Deadlock)。