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.wait和Atomics.notify),适用于底层的数值同步,但不建议在 UI 线程使用Atomics.wait,因为它会物理阻塞线程。
3. 共享与锁的选择维度
| 需求场景 | 推荐方案 | 性能损耗 |
|---|---|---|
| 传递少量配置信息 | 普通对象(序列化拷贝) | 高(随数据量增大) |
| 大数据块(如像素数据) | SharedArrayBuffer | 极低(零拷贝) |
| 复杂业务模型共享 | @Sendable 对象 | 极低(引用传递) |
| 多线程竞争修改数据 | AsyncLock | 低(异步排队,无阻塞) |
架构师总结
ArkTS 的设计理念是 “能隔离就隔离,必须共享则加锁” 。
- UI 安全优先:即便有了共享内存,也不建议在主线程频繁加锁。
- 避免死锁:由于
AsyncLock是异步的,它能有效避免传统多线程开发中常见的循环等待导致的死锁(Deadlock)。