HarmonyOS 鸿蒙Next多线程并发
HarmonyOS 鸿蒙Next多线程并发
ArkTS多线程下如何实现单例以及保证并发安全
还有一个方案:
-
实现方案介绍 步骤一:使用ArkTS对象定义Sendable类的单例,封装为共享模块(进程内共享),并在子线程中初始化。
步骤二:初始化完成后通知主线程,主线程使用该单例对象。
-
业务实现中的关键点 Sendable类需要满足一定的约束,可参考@Sendable装饰器。
-
案例参考
// Demo.ets
"use shared"
@Sendable
export class Demo {
private static instance: Demo;
private constructor() {
}
public static getInstance(): Demo {
if (!Demo.instance) {
Demo.instance = new Demo();
}
return Demo.instance;
}
public init(): void {
// initialization logic
}
}
import { BusinessError } from '@kit.BasicServicesKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { taskpool } from '@kit.ArkTS';
import { Demo } from './demo';
const DOMAIN = 0x0000;
const TAG = 'InterthreadCommunication3';
const FORMAT = '%{public}s';
@Concurrent
function initSingleton(): void {
let demo = Demo.getInstance();
demo.init();
// Notify the main thread that initialization is complete
}
async function executeTaskPool(): Promise<void> {
let task = new taskpool.Task(initSingleton);
await taskpool.execute(task).catch((err: BusinessError) => {
hilog.error(DOMAIN, TAG, FORMAT, `taskpool execute error. Cause code: ${err.code},message: ${err.message}`);
});
}
executeTaskPool();
更多关于HarmonyOS 鸿蒙Next多线程并发的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
线程间模块共享(单例模式)
-
场景描述
进程的唯一ArkTS实例初始化流程复杂,整体耗时较长。如果在主线程中进行初始化,会导致应用启动时间延长并阻塞主线程的执行。因此,建议将这些实例的初始化流程放在ArkTS子线程中进行。初始化完成后,主线程可以直接使用该实例。常见的业务场景如下所示:
| 常见业务场景 | 具体业务描述 |
|---|---|
| SDK初始化 | 在ArkTS子线程中调用API的Init初始化得到一个单例对象,完成后传给其他ArkTS线程使用 |
-
实现方案介绍
步骤一:使用C++单例模式封装,并在上层封装JS壳,子线程中进行初始化。步骤二:初始化完成后通知主线程,主线程导入并使用该单例对象。

-
业务实现中的关键点
a. JS模块对象
模块定义的导出对象即为使用者导入时获得的对象。JS模块对象中的JS函数通过Node-API方法绑定到模块的Native静态方法。调用JS函数时,实际会调用Native静态方法来提供功能。
b. Native Instance
模块对象的成员对象(ExternalReference)通过Native Class的GetCurrentInstance(标准单例实现)获取,进程内同模块均指向同一个Native单例。此设计适用于已有线程安全C++类的Native实现,Native成员方法需进行同步保护。该模块对象即使包含其他JS成员,也类似于"局部变量",即线程间不共享。
c. Native静态方法
Native静态方法提供对应模块的Native功能实现。通过napi_get_cb_info获取JS绑定函数的this对象,从而通过this获取绑定在JS模块对象上的Native实例,再调用Native实例对应的Native成员方法,即可完成对应功能的实现。说明
同上,方法实现中不能进行非线程安全的全局变量操作。
d. 生命周期问题
模块对象通常在主线程退出时进行析构。若需精细化控制,可以绑定finalizeCallback进行管理。线程对象回收时,该线程会调用析构方法。
-
案例参考
// napi_init.cpp
class Singleton {
public:
static Singleton &GetInstance() {
static Singleton instance;
return instance;
}
static napi_value GetAddress(napi_env env, napi_callback_info info) {
uint64_t addressVal = reinterpret_cast<uint64_t>(&GetInstance());
napi_value napiAddress = nullptr;
napi_create_bigint_uint64(env, addressVal, &napiAddress);
return napiAddress;
}
static napi_value GetSetSize(napi_env env, napi_callback_info info) {
std::lock_guard<std::mutex> lock(Singleton::GetInstance().numberSetMutex_);
uint32_t setSize = Singleton::GetInstance().numberSet_.size();
napi_value napiSize = nullptr;
napi_create_uint32(env, setSize, &napiSize);
return napiSize;
}
static napi_value Store(napi_env env, napi_callback_info info) {
size_t argc = 1;
napi_value args[1] = {nullptr};
napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
if (argc != 1) {
napi_throw_error(env, "ERROR: ", "store args number must be one");
return nullptr;
}
napi_valuetype type = napi_undefined;
napi_typeof(env, args[0], &type);
if (type != napi_number) {
napi_throw_error(env, "ERROR: ", "store args is not number");
return nullptr;
}
std::lock_guard<std::mutex> lock(Singleton::GetInstance().numberSetMutex_);
uint32_t value = 0;
napi_get_value_uint32(env, args[0], &value);
Singleton::GetInstance().numberSet_.insert(value);
return nullptr;
}
private:
Singleton() {} // Private constructor to prevent external instantiation of objects
Singleton(const Singleton &) = delete; // Do not copy the constructor
Singleton &operator=(const Singleton &) = delete; // The assignment operator is prohibited
public:
std::unordered_set<uint32_t> numberSet_{};
std::mutex numberSetMutex_{};
};
// Index.ets
import { taskpool } from '@kit.ArkTS';
import singleton from 'libentry.so';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { BusinessError } from '@kit.BasicServicesKit';
// ...
@Concurrent
function getAddress() {
let address = singleton.getAddress();
hilog.info(0x0000, 'TAG', '%{public}s', 'taskpool:: address is ' + address);
}
@Concurrent
function store(a: number, b: number, c: number) {
let size = singleton.getSetSize();
hilog.info(0x0000, 'TAG', '%{public}s', 'set size is ' + size + ' before store');
singleton.store(a);
singleton.store(b);
singleton.store(c);
size = singleton.getSetSize();
hilog.info(0x0000, 'TAG', '%{public}s', 'set size is ' + size + ' after store');
}
@Entry
@Component
struct Index {
build() {
Row() {
Column() {
Button('TestSingleton')
.onClick(() => {
let address = singleton.getAddress();
hilog.info(DOMAIN, TAG, FORMAT, `host thread address is ${address}`);
let task1 = new taskpool.Task(getAddress);
taskpool.execute(task1).catch((err: BusinessError) => {
hilog.error(DOMAIN, TAG, FORMAT,
`taskpool execute error. Cause code: ${err.code},message: ${err.message}`);
});
let task2 = new taskpool.Task(store, 1, 2, 3);
taskpool.execute(task2).catch((err: BusinessError) => {
hilog.error(DOMAIN, TAG, FORMAT,
`taskpool execute error. Cause code: ${err.code},message: ${err.message}`);
});
let task3 = new taskpool.Task(store, 4, 5, 6);
taskpool.execute(task3).catch((err: BusinessError) => {
hilog.error(DOMAIN, TAG, FORMAT,
`taskpool execute error. Cause code: ${err.code},message: ${err.message}`);
});
})
}
.width('100%')
}
.height('100%')
}
}
HarmonyOS Next多线程并发基于Actor模型实现线程间通信,通过TaskPool和Worker提供并行任务处理能力。TaskPool适用于无状态任务分发,支持负载均衡;Worker用于有状态任务,维护独立线程上下文。系统提供线程间对象序列化传输机制,支持Promise异步编程模式。并发操作需遵循线程安全规范,通过Sendable接口约束跨线程数据传递。


