多线程简介
1个进程中可以开启多条线程,每条线程可以并行(同时)执行不同的任务,提高程序的执行效率。
进程
- 进程是指在系统中正在运行的一个应用程序
- 每个进程之间是独立的,每个进程均运行在其专用且受保护的内存空间内
线程
- 一个进程要想执行任务,必须得有线程(
每1个进程至少要有1条线程) - 一个进程(程序)的所有任务都在线程中执行
线程串行
- 一个一个的按顺序执行
进程和线程的比较
- 线程是CPU调用(执行任务)的最小单位
- 进程是CPU分配资源和调度的单位
- 一个程序可以对应多个进程,一个进程中可以有多个线程,但至少要有一个线程
- 同一个进程内的线程共享进程的资源
多线程原理
- 同一时间,CPU只能处理1条线程,只有1条线程在工作(执行)
- 多线程并发(同时)执行,其实是CPU快速地在多条线程之间调度(切换)
- 如果CPU调度线程的时间足够快,就造成了多线程并发执行的假象
iOS中多线程的实现方案

线程的状态和安全
线程状态

// 控制线程状态
// 启动线程 - 进入就绪状态 -> 运行状态。当线程任务执行完毕,自动进入死亡状态
- (void)start;
// 阻塞(暂停)线程 - 进入阻塞状态
+ (void)sleepUntilDate:(NSDate *)date;
+ (void)sleepForTimeInterval:(NSTimeInterval)ti;
// 强制停止线程 - 进入死亡状态
+ (void)exit;
线程安全

互斥锁 @synchronized(锁对象) { // 需要锁定的代码 }
原子和非原子属性
atomic:原子属性(默认)nonatomic:非原子属性
NSThread
// 1.1 创建、启动线程
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];
[thread start];
// 1.2 其他创建线程方式(优点:简单快捷; 缺点:无法对线程进行更详细的设置 )
[NSThread detachNewThreadSelector:@selector(run) toTarget:self withObject:nil]; // 创建线程后自动启动线程
[self performSelectorInBackground:@selector(run) withObject:nil]; // 隐式创建并启动线程
// 生命周期:当任务执行完毕之后会被释放掉
线程间通信
[self performSelectorOnMainThread:@selector(showImage:) withObject:image waitUntilDown:NO]; // 方式一
[self performSelector:@selector(showImage:) onThread:[NSThread mainThread] withObject:image waitUntilDown:NO]; // 方式二
[self.imageView performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDown:NO]; // 方式三
NSOperation
NSOperation和NSOperationQueue实现多线程的具体步骤
- 先将需要执行的操作封装到一个
NSOperation对象中 - 然后将
NSOperation对象添加到NSOperationQueue中 - 系统会自动将
NSOperationQueue中的NSOperation取出来 - 将取出的
NSOperation封装的操作放到一条新线程执行
NSOperation 是个抽象类,不具备封装操作的能力,必须使用其子类:NSInvocationOperation、NSBlockOperation
NSOperationQueue的基本使用
/**
NSOperation:
取主队列:[NSOperationQueue mainQueue]; 和GCD中的主队列一样
非主队列:[[NSOperationQueue alloc] init]; 非常特殊(同时具备并发和串行的功能)默认是并发
*/
NSOperationQueue *queue = [[NSOperationQueue alloc] init]; // 默认并发队列
queue.maxConcurrentOperationCount = 5; // 设置最大并发数量(等于1时则串行执行任务 != 只开一条线程)
NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
// 执行任务
}];
[queue addOperation:op1]; // 会自动执行start
[queue setSuspended:YES]; // 暂停 (不能暂停当前正在执行状态的任务)
[queue setSuspended:NO]; // 继续执行
[queue cancelAllOperations];// 取消
// 操作依赖,不能循环依赖,可以跨队列依赖 例:
[op1 addDependency:op4];
[op4 addDependency:op2];
[op2 addDependency:op3];
// 上面依赖执行顺序为: op3 -> op2 -> op4 -> op1
// 操作监听
op3.completionBlock = ^{
// op3执行完成后执行该监听回调,这里面不跟op3中的任务不一定是同一线程中
}
GCD
GCD基本知识
- 两个核心概念 -
任务和队列 同步函数(不具备开启新线程能力)和异步函数(具备开启新线程能力)并发队列和串行队列
GCD基本使用

// 创建队列 - DISPATCH_QUEUE_SERIAL:串行 / DISPATCH_QUEUE_CONCURRENT:并发
dispatch_queue_t queue = dispatch_queue_create("com.ltd.download", DISPATCH_QUEUE_SERIAL);
// 获取全局并发队列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// 获取主队列
dispatch_queue_t queue = dispatch_get_main_queue();
GCD其他函数
/**
1.延迟执行
第一个参数:DISPATCH_TIME_NOW 从现在开始计算时间
第二个参数:延迟的时间 2.0 GCD时间单位:纳秒
第三个参数:队列
*/
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
// 执行任务
});
// 2.执行一次
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// 执行任务
});
// 3.栅栏函数(控制任务的执行顺序)(注意:栅栏函数不能使用全局并发队列)
dispatch_barrier_async(queue, ^{
// 执行任务
});
/**
4.快速迭代 (开子线程和主线程一起完成遍历任务,任务的执行是并发的)
第一个参数:遍历的次数
第二个参数:队列(只能是并发队列,不然没啥作用或死锁)
第三个参数:index 索引
*/
dispatch_apply(10, dispatch_get_global_queue(0, 0), ^(size_t index) {
// 执行任务
});
// 5.队列组
dispatch_group_t group = dispatch_group_create(); // 创建队列组
dispatch_group_async(group, queue, dispatch_block_t block); // 任务
dispatch_group_notify(group, queue, dispatch_block_t block); // 队列组中的任务执行完毕之后,执行该函数
dispatch_group_wait(group, DISPATCH_TIME_FOREVER); // 死等