在编程中,引入对象互斥锁的概念,来保证共享数据操作的完整性。每个对象都对应于一个可称为“互斥锁”的标记,这个标记用来保证在任一时刻,只能有一个线程访问对象。1.1 @synchronized (self)- (void)lock1 { @synchronized (self) { // 加锁操作 }}复制代码1.2 NSLock- (void)lock2 { NSLock *xwlock = [[NSLock alloc] init]; XWLogBlock logBlock = ^ (NSArray *array) { [xwlock lock]; for (id obj in array) { NSLog(@"%@",obj); } [xwlock unlock]; }; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ NSArray *array = @[@1,@2,@3]; logBlock(array); });}复制代码1.3 pthread
pthread除了创建互斥锁,还可以创建递归锁、读写锁、once等锁__block pthread_mutex_t mutex; pthread_mutex_init(&mutex, NULL); dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ NSLog(@"+++++ 线程1 start"); pthread_mutex_lock(&mutex); sleep(2); pthread_mutex_unlock(&mutex); NSLog(@"+++++ 线程1 end"); }); dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ NSLog(@"----- 线程2 start"); pthread_mutex_lock(&mutex); sleep(3); pthread_mutex_unlock(&mutex); NSLog(@"----- 线程2 end"); });}复制代码2. iOS中的递归锁
同一个线程可以多次加锁,不会造成死锁死锁->- (void)lock5 { NSLock *commonLock = [[NSLock alloc] init]; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ static void (^XWRecursiveBlock)(int); XWRecursiveBlock = ^(int value) { [commonLock lock]; if (value > 0) { NSLog(@"加锁层数: %d",value); sleep(1); XWRecursiveBlock(--value); } NSLog(@"程序退出!"); [commonLock unlock]; }; XWRecursiveBlock(3); });}复制代码<-死锁2.1 NSRecursiveLock- (void)lock4 { NSRecursiveLock *recursiveLock = [[NSRecursiveLock alloc] init]; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ static void (^XWRecursiveBlock)(int); XWRecursiveBlock = ^(int value) { [recursiveLock lock]; if (value > 0) { NSLog(@"加锁层数: %d",value); sleep(1); XWRecursiveBlock(--value); } NSLog(@"程序退出!"); [recursiveLock unlock]; }; XWRecursiveBlock(3); });}复制代码2.2 pthread- (void)lock6 { __block pthread_mutex_t recursiveMutex; pthread_mutexattr_t recursiveMutexattr; pthread_mutexattr_init(&recursiveMutexattr); pthread_mutexattr_settype(&recursiveMutexattr, PTHREAD_MUTEX_RECURSIVE); pthread_mutex_init(&recursiveMutex, &recursiveMutexattr); dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ static void (^XWRecursiveBlock)(int); XWRecursiveBlock = ^(int value) { pthread_mutex_lock(&recursiveMutex); if (value > 0) { NSLog(@"加锁层数: %d",value); sleep(1); XWRecursiveBlock(--value); } NSLog(@"程序退出!"); pthread_mutex_unlock(&recursiveMutex); }; XWRecursiveBlock(3); });}复制代码3. 信号量
信号量(Semaphore),有时被称为信号灯,是在多线程环境下使用的一种设施,是可以用来保证两个或多个关键代码段不被并发调用。在进入一个关键代码段之前,线程必须获取一个信号量;一旦该关键代码段完成了,那么该线程必须释放信号量。其它想进入该关键代码段的线程必须等待直到第一个线程释放信号量3.1 dispatch_semaphore_t实现 GCD 下同步- (void)lock7 {// dispatch_semaphore_create //创建一个信号量 semaphore// dispatch_semaphore_signal //发送一个信号 信号量+1// dispatch_semaphore_wait // 等待信号 信号量-1 /// 需求: 异步线程的两个操作同步执行 dispatch_semaphore_t semaphone = dispatch_semaphore_create(0); NSLog(@"start"); dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ NSLog(@"async .... "); sleep(5); /// 线程资源 + 1 dispatch_semaphore_signal(semaphone);//信号量+1 }); /// 当前线程资源数量为 0 ,等待激活 dispatch_semaphore_wait(semaphone, DISPATCH_TIME_FOREVER); NSLog(@"end");}复制代码3.2 pthread- (void)lock8 { __block pthread_mutex_t semaphore = PTHREAD_MUTEX_INITIALIZER; __block pthread_cond_t cond = PTHREAD_COND_INITIALIZER; NSLog(@"start"); dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ pthread_mutex_lock(&semaphore); NSLog(@"async..."); sleep(5); pthread_cond_signal(&cond); pthread_mutex_unlock(&semaphore); }); pthread_cond_wait(&cond, &semaphore); NSLog(@"end");}复制代码4. 条件锁4.1 NSCondition
NSCondition 的对象实际上是作为一个锁和线程检查器,锁主要是为了检测条件时保护数据源,执行条件引发的任务。线程检查器主要是根据条件决定是否继续运行线程,即线程是否被阻塞。
读写锁实际是一种特殊的自旋锁,它把对共享资源的访问者划分成读者和写者,读者只对共享资源进行读访问,写者则需要对共享资源进行写操作。这种锁相对于自旋锁而言,能提高并发性,因为在多处理器系统中,它允许同时有多个读者来访问共享资源,最大可能的读者数为实际的逻辑CPU数。写者是排他性的,一个读写锁同时只能有一个写者或多个读者(与CPU数相关),但不能同时既有读者又有写者。5.1 dispatch_barrier_async / dispatch_barrier_sync有一个需求,如图:
YYKit作者的文章 不再安全的 OSSpinLock有说到这个自旋锁存在优先级反转的问题。6.2 os_unfair_lock
自旋锁已经不再安全,然后苹果又整出来个 os_unfair_lock_t ,这个锁解决了优先级反转的问题。os_unfair_lock_t unfairLock; unfairLock = &(OS_UNFAIR_LOCK_INIT); os_unfair_lock_lock(unfairLock); os_unfair_lock_unlock(unfairLock);复制代码7. property - atomic / nonatomic
atomic 修饰的对象,系统会保证在其自动生成的 getter/setter 方法中的操作是完整的,不受其他线程的影响。例如 A 线程在执行 getter 方法时,B线程执行了 setter 方法,此时 A 线程依然会得到一个完整无损的对象。atomic
默认修饰符会保证CPU能在别的线程访问这个属性之前先执行完当前操作读写速度慢线程不安全 - 如果有另一个线程 D 同时在调[name release],那可能就会crash,因为 release 不受 getter/setter 操作的限制。也就是说,这个属性只能说是读/写安全的,但并不是线程安全的,因为别的线程还能进行读写之外的其他操作。线程安全需要开发者自己来保证。nonatomic
不默认速度更快线程不安全如果两个线程同时访问会出现不可预料的结果。8. Once 原子操作8.1 GCD- (id)lock15 { static id shareInstance; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ if (!shareInstance) { shareInstance = [[NSObject alloc] init]; } }); return shareInstance;}复制代码8.2 pthread- (void)lock16 { pthread_once_t once = PTHREAD_ONCE_INIT; pthread_once(&once, lock16Func);}void lock16Func() { static id shareInstance; shareInstance = [[NSObject alloc] init];}复制代码
欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) | 黑马程序员IT技术论坛 X3.2 |