下面会以一小个一小个的知识点进行表达(可能想到哪就写到哪)
1.每一个程序都相当于一个进程,每个进程,系统都会为其分配独立的内存空间运行,所以,ios中每一个app应用都相当于一个进程。
2.一个进程中运行的所有任务都是在线程(Thread)中进行的,每个进程至少有一个线程,也就是所谓的主线程,(下图)
进程、线程的关系3.app一旦开始运行,就会默认开启一条线程、也就是所谓的“主线程”。主线程的任务一般是:刷新UI;处理UI事件(滑动屏幕、点击....)
4.如果主线程中的操作太多,会造成页面的卡顿、发烫等现象,所以我们会把耗时的任务放在子线程中并发执行,待执行完毕再通知主线程做相应的变化
5.线程是程序执行流的最小单元,是进程中的一个实体。有自己的栈和寄存器.
进阶
多线程的优点:
1.因为可以并发 所以提高了程序的执行效率
2.提高资源的利用率
3.耗时多的任务可以放在线程中,这样不会造成程序卡顿
多线程的缺点:
1.线程越多,CPU在调度线程上的开销就越大,占用的内存空间越大
2.线程越多,程序设计就越复杂,比如线程之间的通信,多线程的数据共享,这些都需要程序的处理,增加了程序的复杂度。
多线程的种类
1.PThread:(C语言)
2.NSThread
3.GCD
4.NSOpreation
NSThread
三种开启方法:
1.动态开启:手动开启
NSThread*thread1 = [[NSThrea dalloc] initWithTarget:selfselector:@selector(doSomething1:) object:(@"NSThread1")];[thread1 start];
2.静态开启:创建好直接开启
[NSThread detachNewThreadSelector:@selector(doSomething2:) toTarget:selfwithObject:(@"NSTread2")];
3.隐式开启:创建后直接开启
[selfperformSelectorInBackground:@selector(doSomething3:) withObject:(@"NSTread3")];
【NSthread currentThread】:当前线程 【NSthread mainThread】:主线程
线程之间通信
//在指定线程上执行操作
[self performSelector:@selector(run) onThread:thread withObject:nilwaitUntilDone:YES];
//在主线程上执行操作
[self performSelectorOnMainThread:@selector(run) withObject:nilwaitUntilDone:YES];
//在当前线程执行操作
[self performSelector:@selector(run) withObject:nil];
GCD(Grand Central Dispatch)
优点:
1.自动管理线程的生命周期
2.可用于多核运算
串行队列:(主队列、主线程)先进先出 当执行完一个任务时候 再接着往下进行下一个任务
并行队列:
异常一如上代码:会崩溃
分析崩溃原因:
所有的程序,默认就一个主队列和一个主线程,因此viewDidLoad函数这段任务就在主队列中同步执行,dispatch_sync...这段代码表示把B处任务加入主队列中,并且同步执行,这就出问题,B处任务要等主队列中同步执行之前的case1这段任务结束后执行,但B处任务在case1这段任务中,case1又要等B处任务执行完才能继续执行。case1任务要等B处完成才能继续,但case1又排在B处前面,这就尴尬了,所以gg了 😂
GCD 重点
只要是串行队列,肯定要等上一个任务执行完成,才能开始下一个任务。但是并行队列当上一个任务开始执行后,下一个任务就可以开始执行。
同步+串行:未开辟新线程,串行执行任务;
同步+并行:未开辟新线程,串行执行任务;
异步+串行:新开辟一条线程,串行执行任务;
异步+并行:开辟多条新线程,并行执行任务;
在主线程中同步使用主队列执行任务,会造成死锁。
GCD延时方法:
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0*NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
// 2.0秒后异步追加任务代码到主队列,并开始执行
NSLog(@"after---%@",[NSThreadcurrentThread]);// 打印当前线程
});
dispatch_once:生命周期只执行一次
此方法一般多用于创建单例的时候
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSLog(@"就一次%@",[NSThreadcurrentThread]);
});
NSOperation(操作) 和 NSOperationQueue(操作队列)
NSOperation(任务)、NSOperationQueue(队列)是OC对GCD的封装。
NSOperation是一个抽象类;但是想要使用操作的话 可以用“NSInvocationOperation”“NSBlockOperation”
NSInvocationOperation和NSBlockOperation 在没有配合NSOperationQueue使用时 都是在当前线程中执行;
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run) object:nil];
[operation start];
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"%@", [NSThread currentThread]); }];
[operation start];
NSOperationQueue的使用
添加任务:
1.- (void)addOperation:(NSOperation *)op;//添加操作任务
2.- (void)addOperationWithBlock:(void (^)(void))block;//不需要先创建操作,直接添加block
根据maxConcurrentOperationCount来控制是并发或者串行
maxConcurrentOperationCount = 1:代表串行
maxConcurrentOperationCount默认是-1;当大于1的时候 代表是并发
NSOperation之间的依赖:B以来A的时候 就等A执行完再执行B;注意不能相互依赖 这样会造成死锁
NSOperation 常用属性和方法
取消操作方法
- (void)cancel;实质是标记 isCancelled 状态。
判断操作状态方法
- (BOOL)isFinished;判断操作是否已经结束。
- (BOOL)isCancelled;判断操作是否已经标记为取消。
- (BOOL)isExecuting;判断操作是否正在在运行。
- (BOOL)isReady;判断操作是否处于准备就绪状态,这个值和操作的依赖关系相关。
操作同步
- (void)waitUntilFinished;阻塞当前线程,直到该操作结束。可用于线程执行顺序的同步。
- (void)setCompletionBlock:(void (^)(void))block;completionBlock 会在当前操作执行完毕时执行 completionBlock。
- (void)addDependency:(NSOperation *)op;添加依赖,使当前操作依赖于操作 op 的完成。
- (void)removeDependency:(NSOperation *)op;移除依赖,取消当前操作对操作 op 的依赖。
@property (readonly, copy) NSArray<NSOperation *> *dependencies;在当前操作开始执行之前完成执行的所有操作对象数组。
5.9 NSOperationQueue 常用属性和方法
取消/暂停/恢复操作
- (void)cancelAllOperations;可以取消队列的所有操作。
- (BOOL)isSuspended;判断队列是否处于暂停状态。 YES 为暂停状态,NO 为恢复状态。
- (void)setSuspended:(BOOL)b;可设置操作的暂停和恢复,YES 代表暂停队列,NO 代表恢复队列。
操作同步
- (void)waitUntilAllOperationsAreFinished;阻塞当前线程,直到队列中的操作全部执行完毕。
添加/获取操作
- (void)addOperationWithBlock:(void (^)(void))block;向队列中添加一个 NSBlockOperation 类型操作对象。
- (void)addOperations:(NSArray *)ops waitUntilFinished:(BOOL)wait;向队列中添加操作数组,wait 标志是否阻塞当前线程直到所有操作结束
- (NSArray *)operations;当前在队列中的操作数组(某个操作执行结束后会自动从这个数组清除)。
- (NSUInteger)operationCount;当前队列中的操作数。
获取队列
+ (id)currentQueue;获取当前队列,如果当前线程不是在 NSOperationQueue 上运行则返回 nil。
+ (id)mainQueue;获取主队列。
附加知识:
队列组 dispatch_group_t
当把队列任务添加进队列组的时候 当所有添加的任务完成的时候 会有通知回调dispatch_group_notify
实际应用案例(下载两张图片,当两张图都下载完成的时候 就行拼接得出新的图片)
实现步骤如下:
1.创建一个队列组:
2.在全局队列异步中添加一个任务(下载image1),并添加进队列组
3.在全局队列中异步添加一个任务(下载image2),并添加进队列组
4.当都下载完成的时候 进行回调dispatch_group_notify (这时候就行图片拼接)
dispatch_barrier_async 栅栏函数:
栅栏函数,使用此方法创建的任务,会查找当前队列中有没有其他任务要执行,如果有,则等待已有任务执行完毕后再执行,同时,在此任务之后进入队列的任务,需要等待此任务执行完成后,才能执行
网友评论