1. 不同类型锁的优缺点分析
NSLock
- 优点:
- 简单易用,在需要锁定的代码前后调用
lock
和 unlock
方法即可。
- 性能较好,适用于简单的同步场景。
- 缺点:
- 不支持递归调用,如果一个线程对同一个锁多次调用
lock
而没有相应次数的 unlock
,会导致死锁。
- 没有提供等待条件变量等高级功能。
@synchronized
- 优点:
- 语法简洁,使用
@synchronized(self)
这样的形式即可锁定一段代码。
- 自动管理锁的生命周期,无需手动调用
lock
和 unlock
,减少了忘记解锁的风险。
- 缺点:
- 性能相对较差,因为它内部实现相对复杂,涉及到对象的散列表操作。
- 无法设置超时时间,如果等待锁的时间过长,可能会导致线程长时间阻塞。
NSCondition
- 优点:
- 功能强大,除了基本的锁功能外,还支持条件变量。可以让线程在满足特定条件时才继续执行,适用于线程间需要协调工作的场景。
- 可以设置等待条件变量的超时时间,避免线程无限期等待。
- 缺点:
- 相比简单的锁,使用起来较为复杂,需要正确处理锁和条件变量的关系。
- 由于功能丰富,实现相对复杂,性能上可能不如简单的锁。
2. 避免死锁的预防策略
2.1 资源分配图算法
- 可以使用资源分配图算法(如银行家算法)来检测和避免死锁。在多线程访问多个资源的场景下,系统可以通过记录每个线程对资源的请求和分配情况,来判断是否会产生死锁。如果一个请求会导致系统进入不安全状态(可能产生死锁),则拒绝该请求。
2.2 按顺序加锁
- 为所有资源分配一个全局的顺序(例如按照资源的内存地址排序)。当多个线程需要访问多个资源时,所有线程都按照这个顺序来获取锁。这样可以避免循环等待资源的情况,从而避免死锁。
2.3 超时机制
- 为获取锁设置一个超时时间。如果在超时时间内没有获取到锁,则放弃当前操作,释放已经获取的锁,并等待一段时间后重试。这样可以避免线程无限期等待锁,从而避免死锁。
3. 代码示例
按顺序加锁示例
#import <Foundation/Foundation.h>
// 假设有两个资源
NSLock *resource1Lock = [[NSLock alloc] init];
NSLock *resource2Lock = [[NSLock alloc] init];
// 线程1
dispatch_queue_t queue1 = dispatch_queue_create("com.example.queue1", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue1, ^{
if ([resource1Lock lockBeforeDate:[NSDate dateWithTimeIntervalSinceNow:1]]) {
if ([resource2Lock lockBeforeDate:[NSDate dateWithTimeIntervalSinceNow:1]]) {
// 访问资源1和资源2
NSLog(@"Thread 1 accessing resources");
[resource2Lock unlock];
}
[resource1Lock unlock];
}
});
// 线程2
dispatch_queue_t queue2 = dispatch_queue_create("com.example.queue2", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue2, ^{
if ([resource1Lock lockBeforeDate:[NSDate dateWithTimeIntervalSinceNow:1]]) {
if ([resource2Lock lockBeforeDate:[NSDate dateWithTimeIntervalSinceNow:1]]) {
// 访问资源1和资源2
NSLog(@"Thread 2 accessing resources");
[resource2Lock unlock];
}
[resource1Lock unlock];
}
});
超时机制示例
#import <Foundation/Foundation.h>
NSLock *resourceLock = [[NSLock alloc] init];
dispatch_queue_t queue = dispatch_queue_create("com.example.queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
if ([resourceLock lockBeforeDate:[NSDate dateWithTimeIntervalSinceNow:1]]) {
// 访问资源
NSLog(@"Thread accessing resource");
[resourceLock unlock];
} else {
NSLog(@"Thread timed out waiting for lock");
}
});