锁的作用就是为了线程安全、 在多线程的时候 如果同时调用一个资源、可能会导致数据
错乱, 例子:FMDB 句柄操作 不能同时出现两个操作 否则会出现数据库锁死
@synchronized 互斥锁
NSRecursiveLock 递归锁
NSConditionLock 条件锁
NSLock 对象锁
dispatch_semaphore 信号量实现加锁
1、@synchronized在两个同步线程中 同时操作一个方法 不加锁的话 如下
_count = 5;
dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
[self dosomething];
});
dispatch_async(queue, ^{
[self dosomething];
});
- (void)dosomething
{
while (1) {
//@synchronized(self){
[NSThread sleepForTimeInterval:1];
if (_count >0) {
_count --;
NSLog(@"_count=%ld, Thread:%@",_count,[NSThread currentThread]);
}else
{
NSLog(@"end Thread:%@",[NSThread currentThread]);
break;
}
// }
}
}
未加锁
2018-03-07 15:09:01.885914+0800 TableViewDemo[8120:268177] _count=4, Thread:<NSThread: 0x604000071700>{number = 3, name = (null)}
2018-03-07 15:09:01.885914+0800 TableViewDemo[8120:268179] _count=3, Thread:<NSThread: 0x60c000078d40>{number = 4, name = (null)}
2018-03-07 15:09:02.889618+0800 TableViewDemo[8120:268179] _count=1, Thread:<NSThread: 0x60c000078d40>{number = 4, name = (null)}
2018-03-07 15:09:02.889618+0800 TableViewDemo[8120:268177] _count=2, Thread:<NSThread: 0x604000071700>{number = 3, name = (null)}
2018-03-07 15:09:03.893241+0800 TableViewDemo[8120:268179] _count=0, Thread:<NSThread: 0x60c000078d40>{number = 4, name = (null)}
2018-03-07 15:09:03.893241+0800 TableViewDemo[8120:268177] end Thread:<NSThread: 0x604000071700>{number = 3, name = (null)}
2018-03-07 15:09:04.897898+0800 TableViewDemo[8120:268179] end Thread:<NSThread: 0x60c000078d40>{number = 4, name = (null)}
加入了互斥锁
2018-03-07 15:10:36.976073+0800 TableViewDemo[8241:269755] _count=4, Thread:<NSThread: 0x60800007c140>{number = 3, name = (null)}
2018-03-07 15:10:37.979788+0800 TableViewDemo[8241:269754] _count=3, Thread:<NSThread: 0x608000261dc0>{number = 4, name = (null)}
2018-03-07 15:10:38.982916+0800 TableViewDemo[8241:269755] _count=2, Thread:<NSThread: 0x60800007c140>{number = 3, name = (null)}
2018-03-07 15:10:39.983438+0800 TableViewDemo[8241:269754] _count=1, Thread:<NSThread: 0x608000261dc0>{number = 4, name = (null)}
2018-03-07 15:10:40.988521+0800 TableViewDemo[8241:269755] _count=0, Thread:<NSThread: 0x60800007c140>{number = 3, name = (null)}
2018-03-07 15:10:41.992316+0800 TableViewDemo[8241:269754] end Thread:<NSThread: 0x608000261dc0>{number = 4, name = (null)}
2018-03-07 15:10:42.994284+0800 TableViewDemo[8241:269755] end Thread:<NSThread: 0x60800007c140>{number = 3, name = (null)}
以上很明显的看到数据错乱了
2、 NSLock 相同的情况
[_mutelock lock];
[NSThread sleepForTimeInterval:1];
if (_count >0) {
_count --;
NSLog(@"_count=%ld, Thread:%@",_count,[NSThread currentThread]);
}else
{
NSLog(@"end Thread:%@",[NSThread currentThread]);
[_mutelock unlock];
break;
}
[_mutelock unlock];
结果:
2018-03-07 15:19:40.867255+0800 TableViewDemo[8817:280242] _count=4, Thread:<NSThread: 0x60400007ebc0>{number = 3, name = (null)}
2018-03-07 15:19:41.869909+0800 TableViewDemo[8817:280238] _count=3, Thread:<NSThread: 0x608000264900>{number = 4, name = (null)}
2018-03-07 15:19:42.871598+0800 TableViewDemo[8817:280242] _count=2, Thread:<NSThread: 0x60400007ebc0>{number = 3, name = (null)}
2018-03-07 15:19:43.872715+0800 TableViewDemo[8817:280238] _count=1, Thread:<NSThread: 0x608000264900>{number = 4, name = (null)}
2018-03-07 15:19:44.873510+0800 TableViewDemo[8817:280242] _count=0, Thread:<NSThread: 0x60400007ebc0>{number = 3, name = (null)}
2018-03-07 15:19:45.874513+0800 TableViewDemo[8817:280238] end Thread:<NSThread: 0x608000264900>{number = 4, name = (null)}
2018-03-07 15:19:46.879986+0800 TableViewDemo[8817:280242] end Thread:<NSThread: 0x60400007ebc0>{number = 3, name = (null)}
3、 递归Block 出现Lock 锁死情况 这个时候就需要用到递归锁
dispatch_async(queue, ^{
static void (^TestBlcok)(int);
TestBlcok = ^(int value){
[_mutelock lock];
if (value > 0) {
[NSThread sleepForTimeInterval:1];
NSLog(@"value=%d, Thread:%@",value,[NSThread currentThread]);
TestBlcok(value-1);
}
[_mutelock unlock];
};
TestBlcok(5);
});
//这段代码是一个典型的死锁情况。在我们的线程中
RecursiveMethod是递归调用的。所以每次进入这个block时,都会去加一次锁
//,而从第二次开始,由于锁已经被使用了且没有解锁,
//所以它需要等待锁被解除,这样就导致了死锁,线程被阻塞住了。调试器中会输出如下信息:
将_mutelock 替换为
_recursiveLock = [[NSRecursiveLock alloc] init];
解决问题
在这种情况下,我们就可以使用NSRecursiveLock。它可以允许同一线程多次加锁,而不会造成死锁。递归锁会跟踪它被lock的次数。每次成功的lock都必须平衡调用unlock操作。只有所有达到这种平衡,锁最后才能被释放,以供其它线程使用。
4、 NSConditionLock 条件锁
dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
for (int i = 0; i<=3; i++) {
[_conditionLock lock];
[_conditionLock unlockWithCondition:i];
NSLog(@"Thread1:%@ i = %d",[NSThread currentThread],i);
sleep(1);
}
});
dispatch_async(queue, ^{
[_conditionLock lockWhenCondition:2];
NSLog(@"Thread2:%@",[NSThread currentThread]);
[_conditionLock unlock];
});
2018-03-07 15:55:47.975921+0800 TableViewDemo[10049:317781] Thread1:<NSThread: 0x608000276500>{number = 3, name = (null)} i = 0
2018-03-07 15:55:48.981407+0800 TableViewDemo[10049:317781] Thread1:<NSThread: 0x608000276500>{number = 3, name = (null)} i = 1
2018-03-07 15:55:49.984681+0800 TableViewDemo[10049:317786] Thread2:<NSThread: 0x604000072c00>{number = 4, name = (null)}
2018-03-07 15:55:49.984672+0800 TableViewDemo[10049:317781] Thread1:<NSThread: 0x608000276500>{number = 3, name = (null)} i = 2
2018-03-07 15:55:50.989460+0800 TableViewDemo[10049:317781] Thread1:<NSThread: 0x608000276500>{number = 3, name = (null)} i = 3
- 信号量
dispatch_semaphore_t
可以控制两个线程之间的交互
dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
//线程1
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
NSLog(@"任务1");
sleep(10);
dispatch_semaphore_signal(semaphore);
});
//线程2
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
sleep(1);
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
NSLog(@"任务2");
dispatch_semaphore_signal(semaphore);
});
结果就是线程1 Sleep 10s 才执行线程二
dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
创建一个信号量、就好比停车位只有一个
网友评论