HarmonyOS 鸿蒙Next TaskPool创建多线程修改单例对象变量失败问题如何解决
HarmonyOS 鸿蒙Next TaskPool创建多线程修改单例对象变量失败问题如何解决
【问题现象】
在TaskPool里对单例的成员变量进行了修改,主线程读取到的仍然是修改前的值。
【背景知识】
共享模块开发指导 参考文档。 并发(指南)参考文档。 多线程并发(指南)参考文档。 【定位思路】
多线程操作第一印象肯定是ArkTS异步能力TaskPool和Worker。
当前ArkTS提供了TaskPool和Worker两种并发能力,TaskPool和Worker都基于Actor并发模型实现。
在Actor并发模型中,不同线程不会使用同一个单例对象。每个线程都有自己独立的内存空间,线程之间通过消息传递机制进行通信,不会直接访问对方的内存空间,在TaskPool中对单例对象的成员变量进行修改后,主线程读取到未修改的值。
TaskPool和worker的多线程方案都是基于Actor并发模型实现的。每个线程都有自己独立的内存空间,修改一个线程的单例对象不会影响到其他线程中的同一个单例对象。
【解决方案】
共享模块可在线程间共享,可以实现在不同线程间操作同一个单例兑现,可以使用共享模块开发。
(1)在共享模块中创建单例。
// SharedModule.ets
import { ArkTSUtils } from '@kit.ArkTS';
"use shared" // 启动共享模块
@Sendable
export class TaskHandle {
private static instance: TaskHandle = new TaskHandle();
private asyncLock: ArkTSUtils.locks.AsyncLock = new ArkTSUtils.locks.AsyncLock();
private testNum: number = 0;
public async testTask(id: number) {
// 共享异步线程操作同一个数据
await this.asyncLock.lockAsync(async () => {
hilog.info(0x0000, 'taskpool', "TaskHandle task id: " + id + ", testNum: " + this.testNum);
this.testNum++;
await this.sleep(1000);
hilog.info(0x0000, 'taskpool', "TaskHandle task id: " + id + ", testNum: " + this.testNum);
})
}
public getTestNum() {
// 获取测试数据
return this.testNum;
}
public sleep(time: number): Promise<void> {
// 模拟延时操作
return new Promise(resolve => setTimeout(resolve, time))
}
static getInstance(): TaskHandle {
// 单例方法
return TaskHandle.instance;
}
}
(2)外部调用单例的入口。
// Index.ets
import { ArkTSUtils, taskpool } from '@kit.ArkTS';
import { TaskHandle } from './SharedModule'
export class Test {
async testTaskpool(): Promise<void> {
// 启动多个线程执行数据操作
let task1: taskpool.Task = new taskpool.Task(func, 1);
let task2: taskpool.Task = new taskpool.Task(func, 2);
let task3: taskpool.Task = new taskpool.Task(func, 3);
await taskpool.execute(task1);
await taskpool.execute(task2);
await taskpool.execute(task3);
hilog.info(0x0000, 'taskpool', "test task api: " + TaskHandle.getInstance().getTestNum());
}
}
@Concurrent
async function func(num: number): Promise<void> {
// 单个异步线程操作
await TaskHandle.getInstance().testTask(num);
}
@Entry
@Component
struct Index {
@State message: string = 'Hello World';
build() {
Row() {
Text(this.message)
.fontSize(50)
.fontWeight(FontWeight.Bold)
.onClick(()=>{
// 启动线程操作
func(0)
let a = new Test()
a.testTaskpool()
})
.width('100%')
}
.height('100%')
}
}
结果如下图所示:
结果如下图所示:
HarmonyOS鸿蒙Next TaskPool创建多线程修改单例对象变量失败问题,通常是由于TaskPool的线程隔离机制导致。在HarmonyOS中,TaskPool线程与主线程不共享ArkTS引擎实例,因此它们无法直接访问或修改主线程中的单例对象。
要解决这个问题,可以考虑以下方案:
- 使用互斥锁(Mutex):在单例模式的实现中引入互斥锁,以保护单例对象的访问和修改,确保线程安全。
- 原子操作:使用原子操作来检查并设置单例对象的指针,以避免多线程同时访问和修改导致的冲突。
- 避免在TaskPool中直接操作单例:如果可能,尽量避免在TaskPool线程中直接修改单例对象。可以通过消息传递等方式,将需要修改的数据从TaskPool线程传递回主线程,再由主线程进行单例对象的修改。
如果问题依旧没法解决请联系官网客服,官网地址是:https://www.itying.com/category-93-b0.html。