2-15.【ArkTS】ArkTS 如何处理并发安全问题?是否允许跨线程更新 UI?后台线程如何通知 UI?

0 阅读2分钟

ArkTS 的并发安全处理是其“高性能”与“高稳定性”平衡点的体现。它通过内存隔离从物理上杜绝了传统多线程中的“抢占”问题,但在应用开发中也引入了更严谨的通信规则。


1. ArkTS 如何处理并发安全?

与 Java 或 C++ 不同,ArkTS 默认采用 Actor 模型(内存隔离)

  • 隔离机制: 每个线程(UI 线程、TaskPool 任务、Worker)都拥有独立的运行实例(引擎实例)。线程之间不共享内存,这意味着你无法在线程 A 中直接修改线程 B 的变量。
  • 无锁化设计: 因为没有共享内存,所以不需要互斥锁(Mutex)来防止脏读,这彻底消除了死锁(Deadlock)风险。
  • @Sendable 装饰器: 如果你确实需要在线程间传递复杂对象,ArkTS 引入了 @Sendable。被装饰的类在跨线程传递时,系统会确保其引用计数和内存访问是线程安全的。

2. 是否允许跨线程更新 UI?

结论:严禁跨线程直接操作 UI。

这是所有主流现代操作系统的共同选择。

  • 原因: UI 组件(如 Text, Button)是非线程安全的。如果允许后台线程直接修改 UI,可能会导致渲染引擎在绘制时发生严重的内存冲突或布局混乱。
  • 限制: 你不能在 TaskPoolWorker 中调用任何 ArkUI 的组件接口。只有 UI 主线程 才有权操作视图树。

3. 后台线程如何通知 UI?

既然不能直接更新,后台线程需要通过“异步消息”将结果发回主线程,由主线程代为执行更新逻辑。

方式 A:TaskPool 的自动返回 (推荐)

taskpool.execute() 会返回一个 Promise。当后台任务执行完毕,结果会自动“漂流”回主线程的 .then() 回调中。

TypeScript

// 主线程
taskpool.execute(myTask).then((result) => {
  this.uiData = result; // 在主线程安全更新 UI
})

方式 B:TaskPool.sendData 实时通知

如果你需要在后台任务进行中(如进度条更新)不断通知 UI,可以使用 sendData

  • 后台: 任务内部调用 taskpool.Task.sendData(progress)
  • 主线程: 通过 task.onReceiveData 接收消息并更新状态。

方式 C:Emitter 事件总线

对于更解耦的场景(如后台下载服务通知任意页面更新),可以使用 Emitter 发送全局事件。


总结

并发特性传统多线程 (Java/C++)ArkTS (HarmonyOS)
内存访问共享内存 (Shared Memory)内存隔离 (Isolated)
同步工具锁、信号量 (Mutex/Lock)消息传递 (Message Passing)
UI 更新需手动切回 UI 线程强制切回 UI 线程
数据安全容易出现竞态条件编译期/运行时强制安全 (@Sendable)

一句话总结: 在 ArkTS 中,后台线程就像是独立工作的办公室,它们通过“发邮件(消息)”告知 UI 主线程任务进度,而主线程则是唯一有权在“黑板(屏幕)”上写画的人。