Dart Lock 使用总结
概述
在Dart中,static Lock _lock = Lock();
通常用于控制异步操作的并发访问,确保某些代码块在同一时间只能被一个异步操作执行。Lock
类来自synchronized
包。
基本概念
什么是Lock?
Lock
是一种同步原语,用于保护共享资源- 在Dart的异步环境中,用于防止多个Future同时访问临界区
- 与传统线程锁不同,Dart的Lock是基于事件循环的
为什么使用static?
dart
class MyService {
static Lock _lock = Lock(); // 类级别的锁,所有实例共享
// 或者
final Lock _instanceLock = Lock(); // 实例级别的锁
}
依赖安装
yaml
dependencies:
synchronized: ^3.1.0
基本用法
1. 基础锁定示例
dart
import 'package:synchronized/synchronized.dart';
class Counter {
static Lock _lock = Lock();
static int _count = 0;
static Future<void> increment() async {
await _lock.synchronized(() async {
// 临界区:同时只能有一个操作执行
final current = _count;
await Future.delayed(Duration(milliseconds: 10)); // 模拟异步操作
_count = current + 1;
print('Count: $_count');
});
}
}
2. 文件操作保护
dart
class FileManager {
static Lock _fileLock = Lock();
static Future<void> writeToFile(String content) async {
await _fileLock.synchronized(() async {
// 确保文件写入操作不会并发执行
print('开始写入文件...');
await Future.delayed(Duration(milliseconds: 100)); // 模拟文件写入
print('文件写入完成: $content');
});
}
}
3. 数据库操作同步
dart
class DatabaseService {
static Lock _dbLock = Lock();
static Future<void> updateUser(String userId, Map<String, dynamic> data) async {
await _dbLock.synchronized(() async {
// 防止同一用户的并发更新操作
print('更新用户 $userId');
await Future.delayed(Duration(milliseconds: 50)); // 模拟数据库操作
print('用户 $userId 更新完成');
});
}
}
高级用法
1. 带返回值的锁定操作
dart
class CacheManager {
static Lock _cacheLock = Lock();
static Map<String, dynamic> _cache = {};
static Future<String> getOrCreate(String key) async {
return await _cacheLock.synchronized(() async {
if (_cache.containsKey(key)) {
return _cache[key];
}
// 模拟创建数据的异步操作
await Future.delayed(Duration(milliseconds: 100));
final value = 'generated_${DateTime.now().millisecondsSinceEpoch}';
_cache[key] = value;
return value;
});
}
}
2. 超时锁定
dart
class TimeoutLockExample {
static Lock _lock = Lock();
static Future<String> processWithTimeout() async {
try {
return await _lock.synchronized(() async {
// 长时间运行的操作
await Future.delayed(Duration(seconds: 2));
return '处理完成';
}).timeout(Duration(seconds: 1));
} on TimeoutException {
return '操作超时';
}
}
}
3. 多个锁的协调使用
dart
class MultiLockExample {
static Lock _lockA = Lock();
static Lock _lockB = Lock();
static Future<void> operationRequiringBothLocks() async {
await _lockA.synchronized(() async {
await _lockB.synchronized(() async {
// 需要两个锁保护的操作
print('执行需要双重保护的操作');
await Future.delayed(Duration(milliseconds: 50));
});
});
}
}
实际应用场景
1. 单例模式实现
dart
class Singleton {
static Lock _lock = Lock();
static Singleton? _instance;
Singleton._internal();
static Future<Singleton> getInstance() async {
return await _lock.synchronized(() async {
if (_instance == null) {
// 模拟复杂的初始化过程
await Future.delayed(Duration(milliseconds: 100));
_instance = Singleton._internal();
}
return _instance!;
});
}
}
2. 资源池管理
dart
class ConnectionPool {
static Lock _poolLock = Lock();
static List<Connection> _availableConnections = [];
static List<Connection> _usedConnections = [];
static Future<Connection> getConnection() async {
return await _poolLock.synchronized(() async {
if (_availableConnections.isEmpty) {
// 创建新连接
await Future.delayed(Duration(milliseconds: 50));
final newConnection = Connection();
_availableConnections.add(newConnection);
}
final connection = _availableConnections.removeAt(0);
_usedConnections.add(connection);
return connection;
});
}
static Future<void> releaseConnection(Connection connection) async {
await _poolLock.synchronized(() async {
_usedConnections.remove(connection);
_availableConnections.add(connection);
});
}
}
class Connection {
// 连接实现
}
3. API限流控制
dart
class RateLimiter {
static Lock _lock = Lock();
static List<DateTime> _requests = [];
static const int maxRequests = 10;
static const Duration timeWindow = Duration(minutes: 1);
static Future<bool> canMakeRequest() async {
return await _lock.synchronized(() async {
final now = DateTime.now();
// 清理过期的请求记录
_requests.removeWhere(
(requestTime) => now.difference(requestTime) > timeWindow,
);
if (_requests.length >= maxRequests) {
return false; // 达到限流阈值
}
_requests.add(now);
return true;
});
}
}
性能考虑
1. 锁的粒度
dart
// ❌ 锁粒度过大
class BadExample {
static Lock _lock = Lock();
static Future<void> processMultipleItems(List<String> items) async {
await _lock.synchronized(() async {
for (final item in items) {
await processItem(item); // 整个循环都被锁定
}
});
}
}
// ✅ 适当的锁粒度
class GoodExample {
static Lock _lock = Lock();
static Future<void> processMultipleItems(List<String> items) async {
for (final item in items) {
await _lock.synchronized(() async {
await processItem(item); // 只锁定必要的部分
});
}
}
}
2. 避免死锁
dart
// ❌ 可能导致死锁
class DeadlockRisk {
static Lock _lockA = Lock();
static Lock _lockB = Lock();
static Future<void> method1() async {
await _lockA.synchronized(() async {
await _lockB.synchronized(() async {
// 操作
});
});
}
static Future<void> method2() async {
await _lockB.synchronized(() async {
await _lockA.synchronized(() async {
// 操作 - 可能死锁
});
});
}
}
// ✅ 避免死锁的方法
class DeadlockFree {
static Lock _masterLock = Lock();
static Future<void> method1() async {
await _masterLock.synchronized(() async {
// 所有需要多重锁定的操作都使用同一个锁
});
}
static Future<void> method2() async {
await _masterLock.synchronized(() async {
// 操作
});
}
}
错误处理
dart
class ErrorHandlingExample {
static Lock _lock = Lock();
static Future<String> safeOperation() async {
try {
return await _lock.synchronized(() async {
// 可能抛出异常的操作
if (DateTime.now().millisecond % 2 == 0) {
throw Exception('模拟错误');
}
return '操作成功';
});
} catch (e) {
print('锁定操作中发生错误: $e');
return '操作失败';
}
}
}
测试和调试
dart
class DebugLockExample {
static Lock _lock = Lock();
static int _operationCount = 0;
static Future<void> debugOperation(String operationId) async {
print('[$operationId] 等待获取锁...');
await _lock.synchronized(() async {
print('[$operationId] 获得锁,开始执行');
_operationCount++;
await Future.delayed(Duration(milliseconds: 100));
print('[$operationId] 操作完成,操作计数: $_operationCount');
});
print('[$operationId] 释放锁');
}
}
最佳实践
- 合理选择锁的作用域 :使用
static
还是实例变量 - 最小化锁定时间:只保护必要的代码段
- 避免在锁内执行长时间操作:特别是I/O操作
- 一致的锁定顺序:避免死锁
- 适当的错误处理:确保异常不会导致锁泄漏
- 性能测试:在高并发场景下测试锁的性能影响
注意事项
- Dart的Lock是基于事件循环的,不是真正的线程锁
- 在Isolate间不能共享Lock实例
- 过度使用锁可能影响异步操作的性能
- 始终考虑是否真的需要锁,有时使用其他并发控制方式更合适
总结
static Lock _lock = Lock();
是Dart中实现异步操作同步控制的重要工具,正确使用可以避免竞态条件,确保数据一致性。关键是理解其异步特性,合理控制锁的粒度,并遵循最佳实践。