【学习总结】【多线程】 多线程概要 & GDC & NSOperation
基本需要知道的 :
进程 : 简单点来说就是,操作系统中正在运行的一个应用程序,每个进程之间是独立的,每个进程均运行在受保护的内存空间内
线程 : 一个进程(进程)想执行任务,必须有线程(所以,每个进程至少有1条线程),线程是进程的基本执行单元.
疑问 : 在一条线程中怎样执行任务? 线程的串行
线程的串行 : 一个线程中任务的执行是串行的(同一时间内,1个线程只能执行一个任务,)
疑问 : 哪有耗时操作怎么办?或者需要同时执行几个任务? 多线程
多线程 : 顾名思义,就是在一个进程中,开启多条线程并行执行任务(同时执行任务) -->实质上原理是,CPU飞速在多条线程中之间调度(切换),看起来一起操作
疑问 : 如果线程非常多,会发生什么情况? 1. CPU调度频率高,消耗大量资源 2.每条线程被调度执行次数降低(效率低)
疑问 : 多线程技术的优缺点 ? 优点 : 1. 适当提高程序执行效率, 2.适当提高系统资源利用率 缺点 : 1. 开启太多,会降低程序性能 2. 开启太多,CPU开销大 3.程序设计非常复杂(线程间的通讯,线程的数据共享)
IOS主线程 : (又称UI线程) 主要作用 :1.显示\刷新UI界面 2.处理UI事件(点击事件,滚动事件,拖拽事件)
疑问 : 多线程技术怎么实现? 方案有哪些? 1.NSThread , 2.GCD , 3.NSOperation
NSThread : OC - 程序员管理(手动创建,销毁) - 面向对象
GCD : C - 自动管理(自动创建,销毁) - 面向对象 - 充分利用设备的多核 - 自动管理多线程
NSOperation : OC - 自动管理(自动创建,销毁) - GCD的高级封装
疑问 : 多线程技术的隐患? 1. 多个线程可能会访问同一块资源,容易引发数据错乱和数据安全 - 安全隐患解决(互斥锁)
疑问 : 什么是线程同步? 为什么需要线程同步? 1.线程同步就是多条线程在同一条线上执行 2.有时候避免多条线程访问同一份资源,就需要加锁,加锁的操作就等于将所有线程访问这个资源应该按顺序来执行.(主要是避免引发数据错乱和数据安全)
1 /* 2 GCD (Grand Central Dispatch)的两个核心概念 3 任务 : 执行什么操作 4 * 用Block来封装任务 5 6 队列 : 用来存放任务 7 * 全局的并发队列 : 可以让任务并发执行 8 9 10 所以 : GCD的使用也就两步 11 12 1 -> 确定想做的事情(确定任务) 13 14 2 -> GCD会自动将队列中得任务取出, 放到对应的线程中执行 15 任务的取出遵循队列的FIFO原则: 先进先出 , 后进后出 16 17 18 19 -------------------------------------队列的创建方式------------------------------------------------- 20 21 // 两个参数, 前面的参数一般用default ,后面参数默认0,暂时没用 22 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 23 24 * 自己创建的串行队列 : 让任务一个接着一个执行 25 // 创建队列名称 , dispatch_queue_t类 注意:cn.cwlng.queue 可以任意写. 26 dispatch_queue_t queue = dispatch_queue_create("cn.cwlng.queue", NULL); 27 28 29 * 主队列 : 让任务在主线程执行 30 // 获取主队列 31 dispatch_queue_t queue = dispatch_get_main_queue(); 32 33 34 ------------------------------------执行任务的函数------------------------------------------------- 35 36 * 同步执行 : 不具备开启新线程的能力 37 dispatch_sync(<#dispatch_queue_t queue#>, <#^(void)block#>) 38 39 * 异步执行 : 具备开启新线程的能力 40 dispatch_async(<#dispatch_queue_t queue#>, <#^(void)block#>) 41 42 43 ------------------------------------常见的组合与它们之间的通讯--------------------------------------- 44 45 * dispatch_async + 全局并发队列 ; 46 47 * dispatch_async + 自己创建的串行队列; 48 49 * 线程间的通讯 50 51 dispatch_async( 52 dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 53 // 执行耗时的异步操作... 54 dispatch_async(dispatch_get_main_queue(), ^{ 55 // 回到主线程,执行UI刷新操作 56 }); 57 58 }); 59 60 ------------------------------------ 延迟执行 ------------------------------------------------- 61 62 63 * 一旦定制好延迟任务后, 不会卡住当前线程 performSelector 64 //afterDelay秒后,执行SEL方法,并传入WithObject参数 65 [self performSelector:<#(SEL)#> withObject:<#(id)#> afterDelay:<#(NSTimeInterval)#>] 66 67 * 利用GCD函数执行延迟执行操作 dispatch_after 68 // 获取默认并发线程 , 注意: 这里获取是并发线程的话,下面就在子线程中执行,如果是主线程,则时间过后,跳回主线程执行操作 69 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 70 // 延迟加载 71 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), queue, ^{ 72 NSLog(@"这里是执行代码的操作"); 73 74 }); 75 76 77 78 ------------------------------------ 一次性代码 ------------------------------------------------- 79 // 一次性代码 80 static dispatch_once_t onceToken; 81 dispatch_once(&onceToken, ^{ 82 // 这里的代码,在程序运行过程中,永远只会执行一次 83 84 }); 85 86 87 88 */ 89 90 91 92 93 94 95 96 97 98 /* 串行队列 99 100 创建方式 : 101 1 -> 使用 dispatch_queue_create函数创建串行队列 102 103 // 创建队列名称 , dispatch_queue_t类 注意:cn.cwlng.queue 可以任意写. 104 dispatch_queue_t queue = dispatch_queue_create("cn.cwlng.queue", NULL); 105 106 107 2 -> 使用主队列(根主线程相关联的队列) 108 109 主队列是GCD自带的一种特殊的串行队列 110 放在主队列中得任务,都会放到主线程中执行 111 112 // 获取主队列 113 dispatch_queue_t queue = dispatch_get_main_queue(); 114 115 */ 116 117 118 119 120 /* 释放内存结论 121 1. 凡是函数名中带有 create \ copy \ new \ retain 等字眼,都应该在不需要使用这个数据的时候进行release 122 2. GCD的数据类型在ARC环境下不需要再作release 123 3. CF(Code Foundation)的数据类型在ARC\MRC环境下都需要在做release 124 125 126 */
GCD 基本操作
四个术语 : 同步, 异步, 并发 , 串行
同步&异步主要影响能不能开启新的线程
* 同步执行 : 在当前线程中执行任务, 不具备开启新线程的能力
dispatch_sync(<#dispatch_queue_t queue#>, <#^(void)block#>)
* 异步执行 : 在新的线程中执行任务 , 具备开启新线程的能力
dispatch_async(<#dispatch_queue_t queue#>, <#^(void)block#>)
并发&串行主要影响 : 任务的执行方式
* 并发队列 : 可以让多个任务并发(同时)执行 (其实就是自动开启多个线程同时执行任务)
* 串行队列 : 让任务一个接着一个地执行 (一个任务执行完后,再执行下一个任务)
问问自己:
什么是GDC?
GDC是(Grand Central Dispatch) 其实就是帮助管理多线程的一套API.
既然是一套API,那么GDC怎么管理多线程?
GDC 有两个核心的概念,任务和队列
任务 : 执行怎样的操作.
队列 : 用来存放任务.
-> 所以 利用GDC管理就是,确定想做的事情(确定任务),然后将任务放到队列中,GDC会自动将队列的任务中拿出来执行
GDC从队列中取出任务,是遵循,先进先出的原则的.
那GDC队列的创建方式有哪一些呢?
-> 首先要知道,队列是分两种形式, 并行队列和串行队列.
并行队列 : 任务在并行队列中会同时执行.
串行队列 : 任务在串行任务中会一个任务一个任务地执行.
-> 需要掌握的三种创建队列的方法(这里总结一下,具体方式请看上面代码块)
* 创建并行队列.一般使用Default模式
* 创建自定义的串行队列.
* 创建系统的主队列.
任务添加进去队列后,队列有什么方式去执行任务呢?
* 同步执行 : 不具备开启新线程的能力
dispatch_sync
* 异步执行 : 具备开启新线程的能力
dispatch_async
执行的过程中,很多时候需要线程之间的通讯,怎么实现线程中得通讯呢?
GDC的方法调用非常方便 , 只需要在线程执行的过程中,也就是那个Block代码块里面
添加你需要通讯的那个线程即可,然后GDC会自动调用Block代码块,实现互相通讯
--------------------------------------------------NSOperation多线程--------------------------------------------------------------------------
1 /* 2 NSOperation & NSOperationQueue 3 1. 队列的类型 4 5 -> 主队列(同步串行执行) 6 * [NSOperation mainQueue] 7 * 添加到"主队列"中的操作,都会放到主线程中执行 8 9 -> 非主队列(默认创建即是异步并发执行) 10 * [[NSOperation alloc] init] 11 * 添加到"非主队列"中的操作,都会放到子线程中执行 12 13 2. 将任务添加到队列中 14 -> - (void)addOperation:(NSOperation *)op; 15 -> - (void)addOperationWithBlock(void (^)(void))block; 16 17 18 3. 队列的常见用法 19 20 -> 设置最大并发数 21 * get方法 - (NSInteger)maxConcurrentOperationCount; 22 * set方法 - (void)setMaxConcurrentOperationCount:(NSInteger)cnt 23 24 25 ->队列其他操作 26 27 * 取消所有的操作 28 [queue cancelAllOperations]; // 取消队列中的所有任务(不可恢复) 29 30 * 暂停所有操作 31 [queue setSuspended:YES]; // 暂停队列中的所有任务 32 33 * 恢复所有操作 34 [queue setSuspended:NO]; // 恢复队列中的所有任务 35 36 37 4. 操作之间的依赖 38 // 设置依赖 39 // B依赖A , C依赖B 40 // 就是等操作A执行完毕后,才能执行B, B执行完后,才能执行C 41 [operationB addDependency:operationA]; 42 [operationC addDependency:operationB]; 43 44 注: * 不能相互依赖 45 * 可以在不同的QUEUE的NSOperation之间创建依赖关系 46 47 48 49 5. 线程之间的通讯 50 51 52 NSOperationQueue *queue = [[NSOperationQueue alloc] init]; 53 [queue addOperationWithBlock:^{ 54 // 1.执行耗时操作 55 56 // 2.回到主线程 57 [[NSOperationQueue mainQueue] addOperationWithBlock:^{ 58 // 在这里执行在主线程的UI界面刷新操作 59 }]; 60 }]; 61 62 63 64 6. 从其他线程回到主线程的方式 65 ->perform 66 * performSelectorOnMainThread 67 68 69 ->GCD 70 * dispatch_async(dispatch_get_main_queue(), ^{ 71 72 }); 73 74 ->NSOperationQueue 75 * [[NSOperationQueue mainQueue] addOperationWithBlock:^{ 76 77 }]; 78 79 80 81 82 */
NSOperation&NSOperationQueue是什么?
以GDC为底层,比GDC多了一些更简单实用的功能,并且更加面向对象的一套线程技术
怎么操作NSOperation?
和GDC一样, 也有队列和任务(操作)两个概念
通过操纵NSOperationQueue(队列),并且修改队列的某些属性,从而控制整个线程管理
创建队列的方式有两种 一是主队列,也就是主线程队列(同步串行队列) ,二是非主队列(默认异步并发队列)