在了解多线程之前,我们需要先认识一下什么是 进程 和 线程。
**进程:**是在系统中运行的一个程序,每个进程之间是独立的,每个进程均运行在其专有且受保护的内存空间内。
**线程:**一个进程想要执行任务,必须得有线程(至少一个线程),线程是进程的基本执行单元,一个进程的所有任务都必须在线程中执行。
**线程的串行:**一个线程中任务的执行是串行的,如果要在一个线程中执行多个任务,只能一个一个的按顺序执行。
那么如何多个任务同时进行?这 便引出了我们的多线程!
一、多线程
###1.基本概念
一个进程中可以开启多个线程,每个线程可以并发/并行执行不同的任务,多线程可以提交程序的执行效率。如下图(同时执行任务ABC):
###2.多线程的原理 同一时间,CPU只能执行一个线程,只有一个线程正在执行,多线程并发执行,其实是CPU快速的在多个线程之间切换。如果CPU的切换线程的时间足够快,就会造成多线程并发执行的假象。
###3.多线程的优缺点
**优点: **(1)能适当的提高程序的执行效率
(2)能适当的提高资源的利用率(CPU,内存)
缺点:(1)开启线程会占用一定的内存空间(主线程1M,子线程0.5M),如果开启过多的线程会占用大量的内存空间,降低程序的性能。
(2)线程越多,CPU在调度线程上的开销就越大。
###4.IOS中的多线程编程技术
IOS中有四种多线程的编程技术:
- NSThread:每个Thread对象对应一个线程,线程的生命周期由我们自己管理,使用较少。
- NSOperation:面向对象的线程技术,基于GCD来实现,生命周期由系统管理,经常使用。
- GCD:基于C语言的框架,可以充分利用多核,是苹果推荐使用的多线程技术,生命周期由系统管理,经常使用。
以上三种编程技术由上至下,抽象度层次是从低到高的,抽象度越高使用越简单,也是Apple最推荐使用的。
二、NSThread
NSThread有二种创建方式
//实方法例
NSThread *thread = [[NSThread alloc]initWithTarget:self self selector:@selector(threadMethod ) object:nil];
[thread start];
//类方法
[NSThread detachNewThreadSelector: @selector (threadMethod ) toTarget:self withObject:nil];
参数解析:
selector :线程执行的方法,只能有一个参数,而且不能有返回值
target :selector消息发送的对象
argument:传输给target的唯一参数,也可以是nil
三、NSOperation
NSOperation的使用有两种方式:一种是使用定义好的两个类:NSInvocationOperation和NSBlockOperation,另一种是继承NSOperation。
1.NSInvocationOperation
创建 NSInvocationOperation
//直接执行会在主线程中顺序执行
NSInvocationOperation * operation_1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run_A) object:nil];
[operation_1 start]; // 启动任务
// 创建一个队列,默认就是并行队列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
// 设置当前最大的执行数,可以控制是并行还串行,为1时就是串行
queue.maxConcurrentOperationCount = 1;
// 将任务添加到队列中任务就自动执行了
[queue addOperation: operation_1];
2.NSBlockOperation
创建NSBlockOperation
// 至少会有一个任务在主线程中执行,其他任务会被放到其他线程中执行
NSBlockOperation *blockOperation_1 = [NSBlockOperation blockOperationWithBlock:^{
[self run_A];
}];
[blockOperation_1 addExecutionBlock:^{
[self run_B];
}];
[opertion start];
###3.继承 NSOperation
#import <Foundation/Foundation.h>
@interface CustomOperation :NSOperation
@end
#import"CustomOperation.h"
-(void)main{
NSLog(@"%@",[NSTread currentThread]);
}
##四、GCD GCD是Apple开发的一个多核编程的解决方法。该方法在MAC OS X10.6首次推出,随后引用到IOS4.0中。GCD是一个替代诸如:NSThread,NSOperationQueue,NSInvocationOperation等技术的很高效和强大的技术。
GCD队列:分为串行队列(DISPATCH_QUEUE_SERIAL)和并⾏队列(DISPATCH_QUEUE_CONCURRENT)。
** 系统提供的GCD队列:**
**主队列:**使用 dispatch_get_main_queue 函数来获取和主线程关联的串行队列
**全局队列:**系统提供的一个全局并行的队列,使用 dispatch_get_global_queue 函数获取
系统提供的dispatch方法:
//主线程执行一次
dispatch_async(dispatch_get_main_queue(), ^{
//task
});
//后台执行
dispatch_async (dispatch_get_global_queue(0,0), ^{
//task
})
//执行一次
static dispatch_once _t onceToken;
dispatch_once(& onceToken,^{
//task
});
//延迟执行
int sec = 2;
dispatch_after(dispatch_time (DISPATCH_TIME_NOW , (int64_t)
(sec * NSEC_PER_SEC)), dispatch_get_main_queue(),^{
//task
})
###1.同步
同步任务:dispatch_sync,会阻塞后面的任务,必需当前任务完成后才能执行下一个
dispatch_sync(dispatch_get_main_queue(), ^{
self.imagView_1.image = [self downloadImage_one];
});
###2.异步
异步执行:dispatch_async,不会阻塞后面的任务,任务会马上返回下一个任务不需要等待,当这个任务完成后会通知主线程.
dispatch_async(dispatch_get_main_queue(), ^{
[self run_D];
});
dispatch_async(dispatch_get_main_queue(), ^{
[self run_B];
});
dispatch_async(dispatch_get_main_queue(), ^{
[self run_C];
});
dispatch_get_main_queue() 获取主队列,主队列中的任务都会在主线程中执行, 是一个串行队列
###3.串行
自定义的串行队列,中异步执行任务,队列会把任务放到一个新的线程中按顺序执行
dispatch_queue_t serialQueue = dispatch_queue_create("串行队列", DISPATCH_QUEUE_SERIAL);
dispatch_async(serialQueue, ^{
[self run_A];
});
dispatch_async(serialQueue, ^{
[self run_B];
});
dispatch_async(serialQueue, ^{
[self run_C];
});
*/
###4.并行
dispatch_get_global_queue() 全局队列,是一个并行队列,可以将队列中的任务放到不同的线程中执行
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
[self run_A];
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
[self run_B];
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self run_C];
});
任务执行的优先级
DISPATCH_QUEUE_PRIORITY_HIGH 2 //最高
DISPATCH_QUEUE_PRIORITY_DEFAULT 0 //中等(默认)
DISPATCH_QUEUE_PRIORITY_LOW (-2) //低
DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN //后台执行
如果在并行队列中同步执行任务,那么这些任务都会在主线程中按顺序执行,也就没有并发性了。
dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self run_A];
});
dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self run_B];
});
dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self run_C];
});
自定义的并行队列中异步执行任务,队列会把任务放到不同的线程中执行
dispatch_queue_t concurrentlQueue = dispatch_queue_create("并行队列", DISPATCH_QUEUE_CONCURRENT);
dispatch_sync(concurrentlQueue, ^{
[self run_A];
});
dispatch_sync(concurrentlQueue, ^{
[self run_B];
});
dispatch_sync(concurrentlQueue, ^{
[self run_C];
});
##五、NSOperation与GCD的区别
**1、底层实现:**GCD的底层是用C来实现的,NSOperation底层从ios4开始也是用的GCD来实现的。
**2、取消任务:**在NSOperationQueue中,我们可以随时取消已经设定要准备执行的任务(当然,已经开始的任务就无法阻⽌了),而GCD没法停止已经加入queue的block(其实是有的,但需要许多复杂的代码)。
** 3、依赖关系:**NSOperation能够方便地设置依赖关系,我们可以让⼀个Operation依赖于另一 个Operation,这样的话尽管两个Operation处于同一个并行队列中,但前者会直到后者执行完毕后再执⾏。
**4、监听任务的执行情况:**我们能将KVO应用在NSOperation中,可以监听一个Operation是否完成或取消,这样子能比GCD更加有效地掌控我们执行的后台任务。
**5、优先级:**在NSOperation中,我们能够设置NSOperation的priority优先级,能够使同一个并行队列中的任务区分先后地执行,⽽在GCD中,我们只能区分不同任务队列的优先级,如果要区分block任务的优先级,也需要大量的复杂代码。
**6、代码复⽤:**我们能够对NSOperation进行继承,在这之上添加成员变量与成员方法,提⾼整个代码的复⽤度,这比简单地将block任务排⼊入执⾏队列更有⾃由度,能够在其之上添加更多⾃定制的功能。
来源:oschina
链接:https://my.oschina.net/u/2891833/blog/743715