- 一个运行中的程序理解为一个进程,进程下面用于执行任务的通道理解为线程,一个进程下面可以有多个线程同时执行不同的任务。
- 单个线程中任务的执行是串行的,同一时间一个线程只能进行一个任务。
实际上CPU在特定时刻只能处理一条线程,CPU在多个线程之间快速的调度,造成一种多个线程同时执行的假象。所以多线程会大量占用CPU资源。
程序运行时默认创建的线程称为主线程,也称为UI线程,用于UI界面的刷新、响应。耗时操作一般放在子线程执行。
- 线程创建后进入就绪状态等待CPU调用,分配的任务执行完毕或强制退出时销毁。也可以使其进入休眠状态。
NSThread
// 创建并启动线程
// 方式一:
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(selector) object:nil];
[thread start];
// 方法二:
[NSThread detachNewThreadSelector:@selector(selector) toTarget:self withObject:nil];
// 方法三:
[self performSelectorInBackground:@selector(selector) withObject:nil];
GCD
- 任务:需要执行的操作
- 队列:用来存放任务,分为并发队列(同时执行)和串行队列(顺序执行)
// 创建队列 参数一:队列名 参数二:队列类型
dispatch_queue_t queue = dispatch_queue_create(<#const char * _Nullable label#>, <#dispatch_queue_attr_t _Nullable attr#>)
// 获得全局并发队列 参数一:队列优先级 参数二:待定参数 传0
dispatch_queue_t queue = dispatch_get_global_queue(<#long identifier#>, <#unsigned long flags#>)
// 获取主队列 队列里的任务都在主线程执行
dispatch_queue_t queue = dispatch_get_main_queue()
// 同步执行方式 在当前线程中执行任务 是即刻执行的 参数一:队列 参数二:任务
dispatch_sync(<#dispatch_queue_t _Nonnull queue#>, <#^(void)block#>)
// 异步执行方式 一般开启新的线程执行任务
dispatch_async(<#dispatch_queue_t _Nonnull queue#>, <#^(void)block#>)
// 分步执行 先执行barrier之前的再执行barrier再执行barrier之后的 全局的并发队列里执行无效
dispatch_barrier_async(<#dispatch_queue_t _Nonnull queue#>, <#^(void)block#>)
// 延时执行 (延迟5.0秒执行)
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
});
// 一次性代码执行 程序运行过程中只调用一次
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// 一次性代码
});
// 快速遍历执行 要在并发队列中执行 参数一:数组的个数 参数二:并发队列 参数三:元素对应的index
dispatch_apply(10, queue, ^(size_t index) {
});
// 添加任务到队列组 参数一:队列组 参数二:队列 参数三:任务
dispatch_group_async(<#dispatch_group_t _Nonnull group#>, <#dispatch_queue_t _Nonnull queue#>, <#^(void)block#>)
// 队列组中的任务都执行完了 会调用下面的方法
dispatch_group_notify(<#dispatch_group_t _Nonnull group#>, <#dispatch_queue_t _Nonnull queue#>, <#^(void)block#>)
线程同步
- 考虑到可能有多个线程同时访问一个文件产生安全隐患,引入互斥锁对文件进行加锁。
@property (nonatomic, strong) NSObject *lock; // 锁对象 由于需要记录锁的状态 所以锁对象应该始终是一个
@synchronized (self.lock) {
// 访问 修改
}
线程间通信
// 调用主线程执行相关方法 第三个参数理解为是否要等到主线程执行完了selector才执行下面的代码
[self performSelectorOnMainThread:@selector(selector) withObject:nil waitUntilDone:YES];
// 在特定线程调用selector
[self performSelector:@selector(selector) onThread:[NSThread mainThread] withObject:nil waitUntilDone:NO];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 耗时操作
dispatch_async(dispatch_get_main_queue(), ^{
// 回到主线程刷新界面
});
});
网友评论