本文同步发表于我的微信公众号,微信搜索 程语新视界 即可关注,每个工作日都有文章更新
鸿蒙(HarmonyOS)开发中,锁机制是保障多线程安全的核心工具,主要包括运行锁(RunningLock)、文件锁、异步锁(AsyncLock)等类型。
一、运行锁(RunningLock)
作用:防止系统进入休眠或屏幕关闭,适用于后台持续任务(如音乐播放、导航)。
1. 核心API
方法 | 说明 | 权限要求 |
---|---|---|
isSupported(type: RunningLockType) | 检查锁类型是否支持 | 无 |
create(name: string, type: RunningLockType) | 创建锁实例 | ohos.permission.RUNNING_LOCK |
lock() | 持锁 | 需已创建锁实例 |
unlock() | 释放锁 | 需已持锁 |
2. 代码示例
import { runningLock } from '@kit.BasicServicesKit';
// 1. 检查支持性
let isSupported = runningLock.isSupported(runningLock.RunningLockType.BACKGROUND);
console.log(`BACKGROUND锁支持: ${isSupported}`);
// 2. 创建并持锁
runningLock.create('music_lock', runningLock.RunningLockType.BACKGROUND)
.then((lock) => {
lock.lock(); // 持锁
console.log('锁已持有,屏幕保持常亮');
// 模拟任务结束后释放
setTimeout(() => {
lock.unlock();
console.log('锁已释放');
}, 5000);
})
.catch((err) => {
console.error('锁操作失败:', err.code);
});
注意:需在module.json5
中声明权限:
{
"requestPermissions": [
{ "name": "ohos.permission.RUNNING_LOCK" }
]
}
二、文件锁
作用:控制多线程/进程对文件的并发访问,分为阻塞式和非阻塞式。
1. 核心API
方法 | 说明 |
---|---|
lock(exclusive?: boolean) | 阻塞式加锁(默认独占锁) |
tryLock(exclusive?: boolean) | 非阻塞式加锁,失败立即返回 |
unlock() | 释放锁 |
2. 代码示例
import fs from '@ohos.file.fs';
// 1. 打开文件
let file = fs.openSync('/data/test.txt', fs.OpenMode.READ_WRITE);
// 2. 加独占锁(阻塞式)
fs.lock(file.fd, true).then(() => {
console.log('文件锁已获取');
// 写入操作
fs.writeSync(file.fd, '写入数据');
// 释放锁
fs.unlock(file.fd);
}).catch((err) => {
console.error('加锁失败:', err);
});
// 3. 非阻塞式尝试加共享锁
if (fs.tryLock(file.fd, false)) {
console.log('共享锁已获取');
fs.unlock(file.fd);
} else {
console.log('加锁失败,文件被占用');
}
三、异步锁(AsyncLock)
作用:解决ArkTS共享容器(如collections.Array
)的线程安全问题。
1. 核心API
方法 | 说明 |
---|---|
lockAsync(callback: () => void) | 异步加锁,执行回调后自动释放 |
tryLock() | 尝试加锁,返回是否成功 |
2. 代码示例
import { ArkTSUtils, collections } from '@kit.ArkTS';
@Concurrent
async function modifyArray(arr: collections.Array<number>, lock: ArkTSUtils.locks.AsyncLock) {
await lock.lockAsync(() => {
arr[0] += 1; // 安全修改
});
}
@Entry
@Component
struct Index {
private lock = new ArkTSUtils.locks.AsyncLock();
private arr = collections.Array.create<number>(1, 0);
build() {
Button('修改数组')
.onClick(async () => {
await modifyArray(this.arr, this.lock);
console.log('数组值:', this.arr[0]);
})
}
}
四、线程间同步锁(TaskPool/Worker)
场景:TaskPool适合独立任务,Worker适合关联任务。
1. TaskPool示例
import { taskpool } from '@kit.ArkTS';
@Concurrent
function syncTask(num: number): number {
// 模拟同步操作
return num * 2;
}
let task = new taskpool.Task(syncTask, 5);
taskpool.execute(task).then((res) => {
console.log('任务结果:', res); // 输出10
});
2. Worker示例
// 主线程
let worker = new worker.ThreadWorker('entry/ets/workers/MyWorker.ts');
worker.postMessage({ type: 'calc', data: 10 });
// Worker线程(MyWorker.ts)
worker.onmessage = (msg) => {
if (msg.type === 'calc') {
let result = msg.data * 2;
worker.postMessage(result);
}
};
五、锁类型对比与选型
锁类型 | 适用场景 | 线程安全 | 是否需要权限 |
---|---|---|---|
RunningLock | 系统资源保持(如CPU/屏幕) | 是 | 需RUNNING_LOCK |
文件锁 | 文件读写同步 | 是 | 无 |
AsyncLock | ArkTS容器操作 | 是 | 无 |
TaskPool/Worker | 多线程任务协调 | 是 | 无 |
六、总结
- 减少锁粒度:尽量缩小加锁代码范围,避免长时间持锁。
- 避免死锁:确保锁的获取和释放成对出现,尤其是异常场景。
- 性能监控:使用HiTraceMeter分析锁竞争情况(API 19+支持) 。