【学习总结】【多线程】 多线程概要 & 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(队列),并且修改队列的某些属性,从而控制整个线程管理

创建队列的方式有两种 一是主队列,也就是主线程队列(同步串行队列) ,二是非主队列(默认异步并发队列)

 

 

 

 

 

 

 

转载于:https://www.cnblogs.com/cwllong/p/4899035.html

你可能感兴趣的