iOS多线程编程——线程锁的使用
2018-03-07 14:47
375 查看
锁是多线程中中最常用的同步工具。
在多线程编程中,不可避免的会遇到同一个资源在多个线程之间共同使用,这时候就需要通过加锁来保证线程的安全。
1、@synchronized 互斥锁(性能较差;适用线程不多,任务量不大的多线程加锁)
(1)加锁的代码尽量少
(2)添加的OC对象必须在多个线程中都是同一对象
(3)优点是不需要显式的创建锁对象,便可以实现锁的机制。
(4)@synchronized块会隐式的添加一个异常处理例程来保护代码,该处理例程会在异常抛出的时候自动的释放互斥锁。所以如果不想让隐式的异常处理例程带来额外的开销,你可以考虑使用锁对象。
2、NSLock 互斥锁(多次调用lock方法会造成死锁)
(1)在Cocoa程序中NSLock中实现了一个简单的互斥锁。
(2)所有锁(包括NSLock)的接口实际上都是通过NSLocking协议定义的,它定义了lock和unlock方法。你使用这些方法来获取和释放该锁。
(3)NSLock类还增加了tryLock和lockBeforeDate:方法;tryLock试图获取一个锁,但是如果锁不可用的时候,它不会阻塞线程,相反,它只是返回NO。
lockBeforeDate:方法试图获取一个锁,但是如果锁没有在规定的时间内被获得,它会让线程从阻塞状态变为非阻塞状态(或者返回NO)。
3、NSRecursiveLock 递归锁(在递归或循环中使用递归锁;递归锁的性能出奇的高,但是只能作为递归使用,所以限制了使用场景)
4、NSConditionLock 条件锁(加锁性能非常低,但是可以用来做多线程处理不同任务的通信调用)
5、pthread_mutex 互斥锁(底层的api,复杂的多线程处理建议使用,并且可以封装自己的多线程)
6、dispatch_semaphore 信号量@interface Person : NSObject
@property (nonatomic, strong) NSString *name;
- (void)showMessage;
@end
@implementation Person
- (void)showMessage
{
NSLog(@"%@, name is %@", [NSThread currentThread], self.name);
}
@end
- (void)threadNSLock
{
// 互斥锁 NSLock 的使用,一个线程的执行需要等待另一个线程解锁后才开始。锁定(lock)和解锁(unLock)必须配对使用。
NSLog(@"互斥锁");
Person *person = [Person new];
person.name = @"iosDev";
Person *person2 = [Person new];
person2.name = @"devZhang";
// 创建锁
NSLock *personLock = [NSLock new];
// 线程A
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
@synchronized(person) {
[personLock lock]; // 加锁
[person showMessage];
[NSThread sleepForTimeInterval:3]; // 线程休眠3秒
[personLock unlock]; // 解锁
}
});
// 线程B
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
@synchronized(person) {
[personLock lock]; // 加锁
[person showMessage];
[personLock unlock]; // 解锁
}
});
// 线程C
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
@synchronized(person2) {
[person2 showMessage];
}
});
}
在多线程编程中,不可避免的会遇到同一个资源在多个线程之间共同使用,这时候就需要通过加锁来保证线程的安全。
1、@synchronized 互斥锁(性能较差;适用线程不多,任务量不大的多线程加锁)
(1)加锁的代码尽量少
(2)添加的OC对象必须在多个线程中都是同一对象
(3)优点是不需要显式的创建锁对象,便可以实现锁的机制。
(4)@synchronized块会隐式的添加一个异常处理例程来保护代码,该处理例程会在异常抛出的时候自动的释放互斥锁。所以如果不想让隐式的异常处理例程带来额外的开销,你可以考虑使用锁对象。
2、NSLock 互斥锁(多次调用lock方法会造成死锁)
(1)在Cocoa程序中NSLock中实现了一个简单的互斥锁。
(2)所有锁(包括NSLock)的接口实际上都是通过NSLocking协议定义的,它定义了lock和unlock方法。你使用这些方法来获取和释放该锁。
(3)NSLock类还增加了tryLock和lockBeforeDate:方法;tryLock试图获取一个锁,但是如果锁不可用的时候,它不会阻塞线程,相反,它只是返回NO。
lockBeforeDate:方法试图获取一个锁,但是如果锁没有在规定的时间内被获得,它会让线程从阻塞状态变为非阻塞状态(或者返回NO)。
3、NSRecursiveLock 递归锁(在递归或循环中使用递归锁;递归锁的性能出奇的高,但是只能作为递归使用,所以限制了使用场景)
4、NSConditionLock 条件锁(加锁性能非常低,但是可以用来做多线程处理不同任务的通信调用)
5、pthread_mutex 互斥锁(底层的api,复杂的多线程处理建议使用,并且可以封装自己的多线程)
6、dispatch_semaphore 信号量@interface Person : NSObject
@property (nonatomic, strong) NSString *name;
- (void)showMessage;
@end
@implementation Person
- (void)showMessage
{
NSLog(@"%@, name is %@", [NSThread currentThread], self.name);
}
@end
- (void)threadSynchronized { // 互斥锁 @synchronized 的使用,锁定的对象为锁的唯一标识,只有标识相同时,才满足互斥。 NSLog(@"互斥锁"); Person *person = [Person new]; person.name = @"iosDev"; Person *person2 = [Person new]; person2.name = @"devZhang"; // 线程A dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ @synchronized(person) { [person showMessage]; [NSThread sleepForTimeInterval:3]; // 线程休眠3秒 } }); // 线程B dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ @synchronized(person) { [person showMessage]; } }); // 线程C dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ @synchronized(person2) { [person2 showMessage]; } }); }
2018-03-07 14:43:43.972 DemoThread[1905:201544] <NSThread: 0x600000273380>{number = 9, name = (null)}, name is iosDev 2018-03-07 14:43:43.972 DemoThread[1905:201556] <NSThread: 0x608000275f80>{number = 10, name = (null)}, name is devZhang 2018-03-07 14:43:46.974 DemoThread[1905:194520] <NSThread: 0x600000273100>{number = 11, name = (null)}, name is iosDev
- (void)threadNSLock
{
// 互斥锁 NSLock 的使用,一个线程的执行需要等待另一个线程解锁后才开始。锁定(lock)和解锁(unLock)必须配对使用。
NSLog(@"互斥锁");
Person *person = [Person new];
person.name = @"iosDev";
Person *person2 = [Person new];
person2.name = @"devZhang";
// 创建锁
NSLock *personLock = [NSLock new];
// 线程A
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
@synchronized(person) {
[personLock lock]; // 加锁
[person showMessage];
[NSThread sleepForTimeInterval:3]; // 线程休眠3秒
[personLock unlock]; // 解锁
}
});
// 线程B
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
@synchronized(person) {
[personLock lock]; // 加锁
[person showMessage];
[personLock unlock]; // 解锁
}
});
// 线程C
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
@synchronized(person2) {
[person2 showMessage];
}
});
}
2018-03-07 14:44:19.925 DemoThread[1905:201556] <NSThread: 0x608000275f80>{number = 10, name = (null)}, name is iosDev 2018-03-07 14:44:19.925 DemoThread[1905:202091] <NSThread: 0x608000274240>{number = 12, name = (null)}, name is devZhang 2018-03-07 14:44:22.930 DemoThread[1905:202090] <NSThread: 0x60800007e540>{number = 13, name = (null)}, name is iosDev
- (void)threadNSRecursiveLock { // 递归锁 NSRecursiveLock 的使用,在递归方法中使用递归锁,否则会造成死锁。 NSLog(@"递归锁"); Person *person = [Person new]; person.name = @"iosDev"; Person *person2 = [Person new]; person2.name = @"devZhang"; // 创建锁对象 NSRecursiveLock *personLock = [[NSRecursiveLock alloc] init]; // 创建递归方法 static void (^testCode)(int); testCode = ^(int value) { [personLock lock]; if (value > 0) { NSLog(@"递归0"); [person showMessage]; [NSThread sleepForTimeInterval:1]; testCode(value - 1); } [personLock unlock]; }; // 线程A dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ testCode(5); }); // 线程B dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ [personLock lock]; NSLog(@"递归1"); [person showMessage]; [personLock unlock]; }); }
2018-03-07 14:44:47.007 DemoThread[1905:202091] 递归0 2018-03-07 14:44:47.007 DemoThread[1905:202091] <NSThread: 0x608000274240>{number = 12, name = (null)}, name is iosDev 2018-03-07 14:44:48.008 DemoThread[1905:202091] 递归0 2018-03-07 14:44:48.009 DemoThread[1905:202091] <NSThread: 0x608000274240>{number = 12, name = (null)}, name is iosDev 2018-03-07 14:44:49.012 DemoThread[1905:202091] 递归0 2018-03-07 14:44:49.013 DemoThread[1905:202091] <NSThread: 0x608000274240>{number = 12, name = (null)}, name is iosDev 2018-03-07 14:44:50.016 DemoThread[1905:202091] 递归0 2018-03-07 14:44:50.017 DemoThread[1905:202091] <NSThread: 0x608000274240>{number = 12, name = (null)}, name is iosDev 2018-03-07 14:44:51.019 DemoThread[1905:202091] 递归0 2018-03-07 14:44:51.019 DemoThread[1905:202091] <NSThread: 0x608000274240>{number = 12, name = (null)}, name is iosDev 2018-03-07 14:44:52.020 DemoThread[1905:202411] 递归1 2018-03-07 14:44:52.020 DemoThread[1905:202411] <NSThread: 0x608000274e40>{number = 14, name = (null)}, name is iosDev
- (void)threadCondition { // 条件锁 NSConditionLock 的使用,只有满足条件的时候才可以解锁。 NSLog(@"条件锁"); Person *person = [Person new]; person.name = @"iosDev"; Person *person2 = [Person new]; person2.name = @"devZhang"; // 创建锁对象 NSConditionLock *personLock = [[NSConditionLock alloc] init]; // 线程A dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ [personLock lock]; // 加锁 [person showMessage]; [NSThread sleepForTimeInterval:3]; [personLock unlockWithCondition:10]; // 符合条件时解锁 }); // 线程B dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ [personLock lockWhenCondition:10]; // 符合条件时加锁 [person showMessage]; [personLock unlock]; // 解锁 }); }
2018-03-07 14:45:22.072 DemoThread[1905:202412] <NSThread: 0x608000272e80>{number = 15, name = (null)}, name is iosDev 2018-03-07 14:45:25.077 DemoThread[1905:202887] <NSThread: 0x608000274bc0>{number = 16, name = (null)}, name is iosDev
- (void)threadCMethod { // C语言方法实现加锁 // 互斥锁 // 互斥锁 + 条件锁 // #import <pthread.h> Person *person = [Person new]; person.name = @"iosDev"; Person *person2 = [Person new]; person2.name = @"devZhang"; // 创建锁对象 NSLog(@"互斥锁"); // 互斥锁 __block pthread_mutex_t personlock; pthread_mutex_init(&personlock, NULL); // 线程A dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ pthread_mutex_lock(&personlock); // 加锁 [person showMessage]; [NSThread sleepForTimeInterval:3]; pthread_mutex_unlock(&personlock); // 解锁 }); // 线程B dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ pthread_mutex_lock(&personlock); [person showMessage]; pthread_mutex_unlock(&personlock); }); NSLog(@"互斥锁 + 条件锁"); // 互斥锁 + 条件锁 __block pthread_cond_t personCodition; pthread_cond_init(&personCodition, NULL); // 线程A dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ pthread_mutex_lock(&personlock); // 加锁 pthread_cond_wait(&personCodition, &personlock); // 条件锁 [person showMessage]; pthread_mutex_unlock(&personlock); // 解锁 }); // 线程B dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ pthread_mutex_lock(&personlock); [person showMessage]; pthread_cond_signal(&personCodition); // 条件锁 [NSThread sleepForTimeInterval:3]; pthread_mutex_unlock(&personlock); }); }
2018-03-07 14:46:07.545 DemoThread[1905:202888] <NSThread: 0x608000274c40>{number = 17, name = (null)}, name is iosDev 2018-03-07 14:46:10.548 DemoThread[1905:203469] <NSThread: 0x608000273c80>{number = 18, name = (null)}, name is iosDev 2018-03-07 14:46:10.548 DemoThread[1905:203471] <NSThread: 0x608000273dc0>{number = 19, name = (null)}, name is iosDev 2018-03-07 14:46:13.552 DemoThread[1905:203470] <NSThread: 0x608000273e80>{number = 20, name = (null)}, name is iosDev
- (void)threadGCD { // 使用 GCD 实现 “ 锁 ” (信号量) GCD提供一种信号的机制,使用它我们可以创建“锁”(信号量和锁是有区别的,具体请自行百度)。 Person *person = [Person new]; person.name = @"iosDev"; Person *person2 = [Person new]; person2.name = @"devZhang"; // 创建并设置信量 dispatch_semaphore_t personGCD = dispatch_semaphore_create(1); // 线程A dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ dispatch_semaphore_wait(personGCD, DISPATCH_TIME_FOREVER); // 等待信号 [person showMessage]; [NSThread sleepForTimeInterval:3]; dispatch_semaphore_signal(personGCD); // 发送信号 }); // 线程B dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ dispatch_semaphore_wait(personGCD, DISPATCH_TIME_FOREVER); // 等待信号 [person showMessage]; dispatch_semaphore_signal(personGCD); // 发送信号 }); }
2018-03-07 14:46:41.194 DemoThread[1905:203472] <NSThread: 0x608000273dc0>{number = 21, name = (null)}, name is iosDev 2018-03-07 14:46:44.194 DemoThread[1905:203982] <NSThread: 0x608000274240>{number = 22, name = (null)}, name is iosDev
相关文章推荐
- 多线程编程之重点--使用DSP/BIOS时选择线程类型的参考方法
- C# 多线程编程 - 使用委托创建线程
- IOS多线程编程之NSOperation和NSOperationQueue的使用
- IOS多线程编程之NSThread的使用
- iOS多线程编程之NSThread的使用
- iOS之多线程编程:三个层次线程应用
- 多线程编程之重点--使用DSP/BIOS时选择线程类型的参考方法
- iOS多线程编程之NSThread的使用
- 多线程编程之重点--使用DSP/BIOS时选择线程类型的参考方法
- iOS多线程编程之NSOperation和NSOperationQueue的使用
- IOS多线程 - 使用线程加载一张图片 - NSThread(1)(转)
- 多线程编程学习3——使用MFC工作者线程
- iOS多线程编程之NSThread的使用
- iOS多线程编程之NSThread的使用
- 多线程编程之使用工作线程实现文档自动保存(II)
- iOS多线程编程之NSOperation和NSOperationQueue的使用 .
- iOS之多线程编程:三个层次线程应用
- iOS多线程编程之NSOperation和NSOperationQueue的使用
- 多线程编程之重点--使用DSP/BIOS时选择线程类型的参考方法
- IOS多线程编程之NSThread的使用