第9章:多线程与并发
并发控制
1. 并发控制概述
在ArkTS中,并发控制是管理多个线程或任务同时访问共享资源的关键机制。合理的并发控制可以避免数据竞争、死锁等问题,确保程序的正确性和性能。
2. 常见的并发控制机制
2.1 锁机制
互斥锁(Mutex)
通过Lock类实现,确保同一时间只有一个线程可以访问共享资源:let lock = new Lock(); lock.lock(); try { // 临界区代码 } finally { lock.unlock(); }读写锁(ReadWriteLock)
允许多个读操作并行,但写操作独占:let rwLock = new ReadWriteLock(); rwLock.readLock().lock(); // 读锁 rwLock.writeLock().lock(); // 写锁
2.2 原子操作
使用Atomic类实现无锁编程,适用于简单变量的线程安全操作:
let atomicCounter = new Atomic<number>(0);
atomicCounter.addAndGet(1); // 原子递增
2.3 信号量(Semaphore)
控制同时访问资源的线程数量:
let semaphore = new Semaphore(3); // 允许3个线程并发
semaphore.acquire();
// 访问资源
semaphore.release();
3. 避免并发问题的实践
3.1 避免死锁
- 锁顺序一致性:所有线程按相同顺序获取锁。
- 超时机制:使用
tryLock(timeout: number)避免无限等待。
3.2 线程安全的数据结构
- 使用
ConcurrentQueue、ConcurrentMap等线程安全容器。
4. 示例:多线程计数器
import { Lock, Atomic, Worker } from '@arkts/core';
class SafeCounter {
private count = new Atomic<number>(0);
private lock = new Lock();
// 原子操作方式
incrementAtomic() {
this.count.addAndGet(1);
}
// 锁方式
incrementLocked() {
this.lock.lock();
try {
this.count.set(this.count.get() + 1);
} finally {
this.lock.unlock();
}
}
}
// 测试代码
const counter = new SafeCounter();
const workers = Array.from({ length: 10 }, () => new Worker(() => {
for (let i = 0; i < 1000; i++) {
counter.incrementAtomic();
}
}));
Promise.all(workers.map(w => w.start())).then(() => {
console.log(`Final count: ${counter.getCount()}`); // 应为10000
});
5. 性能考量
- 锁粒度:尽量缩小临界区范围。
- 无锁编程:在竞争不激烈时优先使用原子操作。
- 线程池:复用线程减少创建/销毁开销。
6. 调试与监控
- 使用
Thread.dumpStack()输出线程堆栈。 - 通过性能分析工具监控锁争用情况。
最佳实践:在ArkTS中,推荐优先使用
Worker线程隔离任务,减少共享状态的需求。必须共享时,选择适合的并发控制机制。
