--------------------多线程--------------------
你理解的多线程?
iOS中的常见多线程方案
技术方案 | 简介 | 语言 | 生命周期 | 使用频率 |
---|---|---|---|---|
pthread | 一套通用的多线程API 适用于Unix\Linux\Windows等系统 跨平台\可移植 使用难度大 |
C | 程序员管理 | 几乎不用 |
NSThread | 使用更加面向对象 简单易用,可直接操作线程对象 |
OC | 程序员管理 | 偶尔使用 |
GCD | 旨在替代NSThread等线程技术 充分利用设备的多核 |
C | 自动管理 | 经常使用 |
NSOperation | 基于GCD(底层是GCD) 比GCD多了一些更简单实用的功能 使用更加面向对象 |
OC | 自动管理 | 经常使用 |
下面打印结果
- (void)viewDidLoad{
[super viewDidLoad];
dispatch_queue_t que = dispatch_get_global_queue(0, 0);
dispatch_async(que, ^{
NSLog(@"1");
[self performSelector:@selector(test) withObject:nil afterDelay:0];
NSLog(@"3");
});
}
- (void)test{
NSLog(@"2");
}
打印结果为1,3.原因:
performSelector:withObject:afterDelay:的本质是往Runloop中添加定时器
子线程默认没有启动Runloop
- (void)test{
NSLog(@"2");
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
NSThread *thread = [[NSThread alloc] initWithBlock:^{
NSLog(@"1");
}];
[thread start];
[self performSelector:@selector(test) onThread:thread withObject:nil waitUntilDone:YES];
}
会crash,因为新开的NSThread运行完之后就不可用了.除非在运行的时候开启它自己的NSRunLoop.那个线程会一直在那跑.
NSRunLoop *currentRunLoop = [NSRunLoop currentRunLoop];
[currentRunLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
GCD常用函数
同步:dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);
异步:dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
并发队列:可以让多个任务并发(同时)执行,并发功能只有在异步(dispatch_async)函数下才有效
串行队列:让任务一个接着一个地执行(一个任务执行完毕后,再执行下一个任务)
同步、异步、并发、串行
同步和异步主要影响:能不能开启新的线程:
同步:在当前线程中执行任务,不具备开启新线程的能力
异步:在新的线程中执行任务,具备开启新线程的能力
并发和串行主要影响:任务的执行方式:
并发:多个任务并发(同时)执行
串行:一个任务执行完毕后,再执行下一个任务
并发队列 | 手动创建的串行队列 | 主队列 | |
---|---|---|---|
同步 | 没有开启新线程 串行执行任务 |
没有开启新线程 串行执行任务 |
没有开启新线程 串行执行任务 |
异步 | 有开启新线程 并发执行任务 |
有开启新线程 串行执行任务 |
没有开启新线程 串行执行任务 |
使用sync函数往当前串行队列中添加任务,会卡住当前的串行队列(产生死锁)
队列组可使用在有任务依赖的地方:dispatch_group_t
多线程的数据安全
多线程的安全主要是通过在写的时候来加锁确保数据的安全,一般情况下都为多读单写,读写分离,读和写不可以同步进行.下面是关于锁的介绍:
自旋锁: 等待锁的线程会处于忙等(busy-wait)状态,一直占用着CPU资源
- 目前已经不再安全,可能会出现优先级反转问题
- 如果等待锁的线程优先级较高,它会一直占用着CPU资源,优先级低的线程就无法释放锁
- 需要导入头文件#import <libkern/OSAtomic.h>
互斥锁: 从底层调用看,等待os_unfair_lock锁的线程会处于休眠状态,并非忙等
- 需要导入头文件#import <os/lock.h>
- 用于取代不安全的OSSpinLock ,从iOS10开始才支持
递归锁: 递归锁有一个特点,就是同一个线程可以加锁N次而不会引发死锁。但是需要成对出现
Foundation系列:
NSLock是对mutex普通锁的封装,NSRecursiveLock也是对mutex递归锁的封装,API跟NSLock基本一致,NSCondition是对mutex和cond的封装,NSConditionLock是对NSCondition的进一步封装,可以设置具体的条件值
你都用过哪些锁(线程同步方案)?结合实际谈谈你是怎样使用的?
性能从高到低:
os_unfair_lock(互斥锁)
OSSpinLock(自旋锁)
dispatch_semaphore(信号量,设置为1代表只允许1条线程访问资源,保证线程同步)
pthread_mutex(互斥锁,等待锁的线程会处于休眠状态.#import <pthread.h>)
dispatch_queue(DISPATCH_QUEUE_SERIAL)(串行队列,实现线程同步)
NSLock
NSCondition
pthread_mutex(recursive)
NSRecursiveLock
NSConditionLock
@synchronized(是对mutex递归锁的封装)
网友评论