文章目录
- 进程与线程
- 多线程
- 总结
进程与线程
进程:具有一定独立功能的程序,是系统进行资源分配与调度的一个独立单位,也就是说进程是可以独立运行的一段程序
- 进程的特点:
- 动态性:进程是程序的一次执行过程,是动态产生,动态消亡的
- 独立性:每个进程都有自己的地址空间,数据栈等运行环境,互不影响
- 并发性:多个进程可以同时存在于内存中,并发执行(宏观并行,微观串行)
- 拥有资源:如内存,文件描述,网络端口,线程本身不拥有这些,而共享同一进程的资源
线程:是进程的一个实体,是cpu调度和分派的基本单位,比进程更小的能独立运行的基本单位
- 线程的特点:
- 轻量级:创建,销毁线程的开销比进程小得多
- 共享资源:多线程共享进程的内存(堆、静态区、文件描述符)每个线程有自己 独立的栈等资源
- 同步问题:因为共享资源,所以同步问题会比较复杂,锁,信号量,原子操作等
二者的关系
- 一个线程只能属于一个进程,而一个进程可以有多个线程,至少会有一个主线程的存在
在iOS中UI的更新必须在主线程
- 资源分配给进程,同一进程的所有线程共享该进程的所有资源
- 不同进程的线程之间要利用消息通信的方法实现同步
- 线程是进程内的一

个执行单元,真正在cpu上运行的是线程
如图在活动检测器上我们能看到一个软件就是一个进程,然后同一个进程会有很多个线程
线程作为调度与分配的基本单位,进程作为拥有资源的基本单位
不仅进程之间可以并发执行,同一个进程的多个线程之间也可以并发执行
进程是拥有资源的一个独立单位,线程不拥有系统资源,但是可以访问属于进程的资源
进程是资源分配的最小单位,线程是cpu调度的基本单位
多线程
同一时间内,单核cpu只能处理一条线程,而我们的多线程执行的时候就是cpu在多线程之间快速进行切换操作,而现在我们使用的基本都是多核cpu,比如我们经常听到的四核八核之类的,而随着多核的使用,多线程并行也可以实现

优缺点
优点
- 可充分利用多核cpu提升效率
- 提升程序的响应速度,避免主线程的卡顿
- 改善程序结构,实现任务分工
- 后台处理能力强,如图片音视频等的解码
缺点
- 多个线程共享同一块内存时,会出现线程安全问题,如重复读写,数据竞争或者崩溃等
可通过加锁,串行队列,信号量等问题解决,但是又会影响性能
- 上下文切换成本高,大量线程并不代表快,有时反而更慢
- 创建和销毁线程需要成本
- 线程太多可能导致系统资源耗尽
- 调试难度变大
线程的状态

线程五大状态:创建 → 就绪 → 运行 → 阻塞 → 终止
-
创建:只是创建了线程对象,线程本体未进入系统调度队列
objcNSThread *t = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];仅分配结构,线程未开始进行
-
就绪:调用了start方法,线程会被加入可调度线程池,等待 CPU 调度,调用 start 不会立即执行线程,它只是进入"可执行但未执行"的状态
-
运行:CPU 调度到该线程时,线程开始执行,CPU 可能随时让线程暂停,线程可能频繁在 就绪和运行之间切换,开发者无法控制什么时候切换
-
阻塞:线程 主动或被动暂停执行,暂时不具备继续运行的条件,如:
-
休眠(sleep):NSThread 提供两种方法
sleepForTimeInterval:休眠指定时长
objc[NSThread sleepForTimeInterval:2]; //休眠2秒sleepUntilDate:休眠到指定时间
objc[NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:5]]; -
同步锁阻塞:
使用 @synchronized(obj) 时:如果锁被其他线程占用,当前线程会被阻塞,等待拿到锁再继续执行
-
-
死亡:线程结束执行,有两种情况,分别是正常终止和非正常终止
- 正常终止,即线程执行完毕
- 非正常终止,即当满足某个条件后,在线程内部(或者主线程中)终止执行(调用exit方法等退出)
多线程实现方案

NSThread
属于手动管理线程方案,需要自己创建,启动,控制
创建线程的三种方式
-
alloc + init + start
objcNSThread *t = [[NSThread alloc] initWithTarget:self selector:@selector(runTask) object:nil]; [t start]; -
detachNewThreadSelector
objc[NSThread detachNewThreadSelector:@selector(runTask) toTarget:self withObject:nil]; -
block
objc[NSThread detachNewThreadWithBlock:^{ [self runTask]; }];
休眠的方法在上面已经给出
线程取消(不会立即停止)
objc
[t cancel];
if ([NSThread currentThread].isCancelled) return;
特点
- 手动创建线程可控性高
- 需要自己管理生命周期麻烦
- 不会自动管理任务依赖、队列组合
- 适合简单线程任务场景
同步、异步、串行、并行
同步 sync
- 不会开新线程
- 阻塞当前线程(必须等任务执行完才往下走)
异步 async
- 可能会开新线程(并不是一定开,看队列类型)
- 不会阻塞当前线程
串行队列 serial
- 一次只执行 一个任务
- 任务 按顺序 执行
并发队列 concurrent
-
可以同时执行多个任务
-
任务可能无序、重叠执行
| 组合 | 是否开线程 | 是否并发 | 是否阻塞当前线程 | 顺序 |
|---|---|---|---|---|
| sync + serial | 否 | 否 | 是 | 是 |
| sync + concurrent | 否 | 否 | 是 | 是 |
| async + serial | 是(1 条) | 否 | 否 | 是 |
| async + concurrent | 是(多条) | 是 | 否 | 否 |
GCD
GCD 是 iOS 多线程的核心,特点是:自动管理线程池,自动管理任务调度,性能最佳
创建队列
串行队列
objc
dispatch_queue_t queue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_SERIAL);
并行队列
objc
dispatch_queue_t queue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_CONCURRENT);
全局队列
objc
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
简单使用
objc
dispatch_async(dispatch_get_global_queue(0, 0), ^{
// 子线程执行耗时操作
dispatch_async(dispatch_get_main_queue(), ^{
// 主线程更新 UI
});
});
dispatch_after(延迟执行)
objc
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
NSLog(@"延迟2秒执行");
});
dispatch_once(单例实现)
objc
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// 只执行一次
});
dispatch_group(任务组)
等待多个线程执行完,再执行某个操作:
objc
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, queue, ^{
// 任务1
});
dispatch_group_async(group, queue, ^{
// 任务2
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
// 所有任务执行结束
});
dispatch_semaphore(信号量)
这里我看别人博客的理解,信号量就是一个类似于保安大爷的东西,他会确保你同时可以执行的线程数量,可以保持线程同步,将异步任务转化为同步执行任务并且保障线程的安全,为线程加锁
objc
dispatch_semaphore_t sema = dispatch_semaphore_create(1);
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
// 访问临界区
dispatch_semaphore_signal(sema);
特点
- 自动线程管理 即不需要创建线程对象
- 性能最好
- API 强大(barrier、group、after、once、semaphore)
- 适合绝大多数多线程任务
NSOperation(比 GCD 更面向对象,功能最强)
NSOperation 是基于 GCD 封装的 面向对象多线程框架
比 GCD 更高级:支持 任务依赖 ;支持 任务暂停/取消 ;支持 最大并发数限制 ;支持 任务队列管理(NSOperationQueue)
使用方式
一、创建Operation
- NSInvocationOperation(调用方法)
objc
NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(runTask) object:nil];
- NSBlockOperation(执行 block)
objc
NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"任务1");
}];
[op addExecutionBlock:^{
NSLog(@"任务2");
}];
-
自定义子类(最强方式)
重写 main 方法:
objc@interface MyOperation : NSOperation @end @implementation MyOperation - (void)main { @autoreleasepool { // 线程任务 } } @end
二、把 Operation 加到队列执行
NSOperationQueue(自动开启线程)
objc
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperation:op];
NSOperationQueue 会自动创建线程并执行任务
队列类型
- 主队列(UI 更新)
- 自定义队列(默认并发)
objc
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
queue.maxConcurrentOperationCount = 2; // 可限制并发数
其他功能
-
添加依赖
一个任务依赖另一个任务执行完:
objc[op2 addDependency:op1]; // op1 执行完,op2 才执行 -
取消操作
objc[op cancel]; -
暂停/继续队列
objcqueue.suspended = YES; // 暂停 queue.suspended = NO; // 继续 -
最大并发数
objcqueue.maxConcurrentOperationCount = 1; // 串行 queue.maxConcurrentOperationCount = 5; // 并发
特点
- 基于 GCD,更面向对象
- 支持依赖、优先级、取消、暂停、最大并发数
- 更适合复杂任务控制
总结
多线程的使用是十分重要的知识点,在后面具体项目中与其他第三方库结合的使用也很多,还需要继续学习并加以实践)