多线程概述
进程:
正在活动(运行的)一个应用程序 就是一个进程
线程:
程序中独立运行的代码段
每一个进程都至少有1条线程 叫主线程 除了主线程以外的 都叫子线程
每一个线程 都是独立的 可以执行任务
子线程可以有 很多个 但是线程是耗费资源的(一般最多不超过5条 注:3条最佳)
程序退出后 会清空线程的任务
主线程可以操作什么样的任务?
UI界面 按钮点击 屏幕的滚动(一切用户看的见的 都要在主线程中去操作 不然就会出现听主线程还是子线程的问题)
子线程可以操作什么样的任务
比较大的耗时操作 又或者 用户看不到的操作 可以放到子线程当中去做 比如下载 解压缩 读取大型数据等 可以在子线程中操作
多线程的原理:
CPU在工作时,同一时间只能执行一个任务 之所以可以造成多条线程一起执行任务的假象 是因为CPU在线程之间进行高速的切换(调度)来达到多个任务一起执行的效果
多线程的优点:
- 可以提高执行任务的效率
- 可以让用户 有更好的用户体验
多线程的缺点:
如果大量的开辟的线程 会造成程序的卡顿 耗费过量的资源
物极必反 盛极而衰
多线程实现种类
- NSObject
- NSThread
- NSOperationQueue
- GCD
NSObject
开辟子线程去执行downLoad:方法 方法是NSObject的 所以一切对象都能够调用
[self performSelectorInBackground:@selector(downLoad:) withObject:@"123"];
子线程完成任务后: 比如请求完数据后 需要回到主线程在UI上面显示
waitUntilDone 是否等待回到主线程的方法执行完毕后 再向下执行
法一:
[self performSelectorOnMainThread: withObject: waitUntilDone:NO];
法二:
[self performSelector: onThread:[NSThread mainThread] withObject:image waitUntilDone:YES];
NSThread
开辟子线程法一:
[NSThread *thread = [NSThread alloc] initWithTarget: selector: object:];
[thread start];
开辟子线程法二:
[NSThread detachNewThreadSelector: toTarget: withObject:];
NSThread的其他方法:
// 获取当前线程
[NSThread currentThread]
// 线程休眠(延迟执行)
[NSThread sleepForTimeInterval:10]
// 立即结束当前线程
// 相当于 你在这里 写了return
// 只要退出当前的线程 后面的一切方法 都不执行了
[NSThread exit];
// 判断当前线程是否为主线程
[NSThread isMainThread]
NSOperation
NSOperation是一个抽象类
他有两个子类: NSInvocationOperation NSBlockOperation
这两个子类都可以开辟子线程去完成某一任务 但是这些任务需要加入到 NSOperationQueue的队列中才能够执行
NSInvocationOperation
// 创建一个队列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
// 给队列提供一个 可以设置的 最大并发数
// 一次最多并发执行2个任务
queue.maxConcurrentOperationCount = 2;
// 开启一个线程(相当于一个任务)
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(downLoad:) object:@"123"];
// 将任务添加到队列中
// 并不是添加一个队列 就开辟一个新线程 线程如何安排靠系统决定(优化)
[queue addOperation:operation];
// 另一种添加方法
[queue addOperationWithBlock:^{
// block中 就是你要添加的任务
}];
NSBlockOperation
// 创建一个队列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
// 给队列提供一个 可以设置的 最大并发数
// 一次最多并发执行2个任务
queue.maxConcurrentOperationCount = 2;
// 初始化一个任务
NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{
// 添加的任务
}];
[queue addOperation:blockOperation];
GCD
队列类型:
- 并行队列 系统提供了一个全局的并行队列(整个应用都可以使用)
- 串行队列 需要创建一个出来
任务:
- 同步: 不具备开启子线程能力
- 异步: 具备开启子线程能力
分四种情况
- 并行 – 异步任务
- 并行 – 同步任务
- 串行 – 异步任务
- 串行 – 同步任务
并行队列处理异步任务
结果: 多个子线程同时处理多个任务
// 获取 全局的并发队列
// dispatch_queue_t 队列的类型
// 参数1 是CPU切换的频率高度(切换的优先级)
// 参数2 是个预留参数 可以填0
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// 添加异步任务
// 参数1 给哪个队列添加任务
dispatch_async(queue, ^{
// 添加任务
});
并行队列处理同步任务
结果: 主线程依次处理任务(相当于串行队列)
// 创建一个 并行队列
// 参数1 队列的标识符 反向域名 com.lanou3g.www
// 参数2 填 你要创建的队列的类型(串/并)
dispatch_queue_t queue = dispatch_queue_create("com.lanou3g.www", DISPATCH_QUEUE_CONCURRENT);
// 添加同步任务
dispatch_sync(queue, ^{
// 添加任务
});
// 创建的队列是需要释放的(ARC 不用释放)
dispatch_release(queue);
串行队列处理异步任务
结果: 某一个子线程处理串行任务
// 创建串行队列
dispatch_queue_t queue = dispatch_queue_create("com.lanou3g.www", DISPATCH_QUEUE_SERIAL);
// 添加异步任务
dispatch_async(queue, ^{
// 添加任务
});
// 创建的队列是需要释放的(ARC 不用释放)
dispatch_release(queue);
串行队列处理同步任务
结果: 同2
dispatch_queue_t queue = dispatch_queue_create("com.lanou3g.www", DISPATCH_QUEUE_SERIAL);
dispatch_sync(queue, ^{
// 添加任务
// 完成任务后回到主线程
dispatch_async(dispatch_get_main_queue(), ^{
// 回到主线程 要执行的任务
// 刷新UI
});
});
// 创建的队列是需要释放的(ARC 不用释放)
dispatch_release(queue);
线程锁
法1:
@synchronized(self) {
// 需要上锁的代码
}
法2:
self.lock = [[NSLock alloc] init];
[lock lock];
// 需要上锁的代码
[lock unlock];