Q. iOS开发中有多少类型的线程?分别对比
- Pthreads // 跨系统c语言多线程框架,不推荐。
- NSTread // 面向对象,需要手动管理生命周期
- GCD :Grand Central Dispatch // 主打任务与队列,告诉他要做什么即可。
- NSOperation & NSOperationQueue // GCD 的封装,面向对象。
Q.GCD和NSOperationQueue对比
GCD是面向底层的C语言API,NSOperationQueue用GCD构建封装的,是GCD的高级抽血。
- GCD执行效率更高,而且由于队列中执行的是由block构成的任务,这是一个轻量级别的数据结构,写起来更方便。
- GCD只支持FIFO的队列,而NSOperationQueue可以用过设置最大并发数,设置优先级,添加依赖关系等调整执行顺序。
- NSOperationQueue甚至可以跨队列设置依赖关系,但是GCD只能通过设置串行队列,或者在队列内添加barrier(dispatch_barrier_async)任务,才能控制执行顺序,较为复杂。
- NSOperationQueue因为面向对象,所以支持KVO,可以监测operation是否在执行(isExecuted)、是否结束(isFinished)、是否取消(isCanceld)
Q.如何实现同步,有多少说多少
- Disaptch_async (在同一个串行队列)
- Dispatch_sync()
- Dispatch_barrier_sync()
- Dispatch_group_create() + dispatch_group_wait()
- Dispatch_apply(1,...)
- NSOperationQueue.maxConcurrentOperationCount = 1
- os_unfair_lock
- Pthread_mutex 互斥锁
- @synchronied
- NSLock
- NSRecursiveLock 递归锁
- NSConditionLock & NSCondition 条件锁
- Dispatch_semaphore_create() + dispatch_semaphore_wait()
Q.dispath_once实现原理
1.读取token值 dispatch_once_t.dgo_once
2.若Block已完成,return
3.若block没有完成,尝试原子性修改dispatch_once_t.dgo_once 值为 DLOCK_ONCE_UNLOCKED
4.修改成功,执行block,原子性修改 dispatch_once_t.dgo_once 为 DLOCK_ONCE_DONE
5.若失败,则进入循环等待。
Q.什么情况下会死锁
-
单线程
对正在执行任务的串行队列添加同步任务
/// 在主线程中执行这句代码 dispatch_sync(dispatch_get_main_queue(), ^{ NSLog(@"这里死锁了"); }); /// 在哪里执行都可以 dispatch_queue_t theSerialQueue = dispatch_queue_create("我是个串行队列", DISPATCH_QUEUE_SERIAL); dispatch_async(theSerialQueue, ^{ /// 正在执行任务,同步异步无所谓 NSLog(@"第一层"); /// 同一个串行队列 dispatch_sync(theSerialQueue, ^{ NSLog(@"第二层"); }); });
- 多线程
简单来说,A等B,同时B等A。
例如某个任务需要多个资源,比如资源1、资源2。此时,线程A和线程B都要执行这个任务。但是,线程A先抢占了资源1,同时线程B抢占了资源2。这个时候,线程A还需要资源2才能执行任务;同样的,线程B需要资源1才能执行任务。于是,A等B,B等A,死锁来了。
- (void)deadLock {
NSThread *thread1 = [[NSThread alloc] initWithTarget:self selector:@selector(deadLock1) object:nil];
[thread1 setName:@"【线程 汤姆】"];
NSThread *thread2 = [[NSThread alloc] initWithTarget:self selector:@selector(deadLock2) object:nil];
[thread2 setName:@"【线程 杰瑞】"];
[thread1 start];
[thread2 start];
}
- (void)deadLock1 {
[self.lock1 lock];
NSLog(@"%@ 锁住 lock1", [NSThread currentThread]);
// 线程休眠一秒
[NSThread sleepForTimeInterval:1];
[self.lock2 lock];
NSLog(@"%@ 锁住 lock2", [NSThread currentThread]);
[self doSomething];
[self.lock2 unlock];
NSLog(@"%@ 解锁 lock2", [NSThread currentThread]);
[self.lock1 unlock];
NSLog(@"%@ 解锁 lock1", [NSThread currentThread]);
}
- (void)deadLock2 {
[self.lock2 lock];
NSLog(@"%@ 锁住 lock2", [NSThread currentThread]);
// 线程休眠一秒
[NSThread sleepForTimeInterval:1];
[self.lock1 lock];
NSLog(@"%@ 锁住 lock1", [NSThread currentThread]);
[self doSomething];
[self.lock1 unlock];
NSLog(@"%@ 解锁 lock1", [NSThread currentThread]);
[self.lock2 unlock];
NSLog(@"%@ 解锁 lock2", [NSThread currentThread]);
}