说明:开发技术大同小异,帖子写出来不是为了晒的,只是一个学习记录过程,有错误欢迎指正,喜欢喷人的请滚蛋。
一、实现方案
在iOS中有三种多线程实现技术,它们分别是NSThread、GCD 、NSOperation。
NSThread:基于OC编写,更加面向对象,可直接操作线程对象,需要程序员手动管理线程生命周期,开发中偶尔使用。
GCD:基于c语言编写,旨在替代NSThread线程技术,能充分利用设备的多核,系统自动管理线程生命周期,开发中经常使用。
NSOperation:底层基于GCD封装的一套OC实现,更加面向对象,系统自动管理线程生命周期,开发中经常使用。
1.NSThread
一个NSthread对象就代表一条线程
相关设置
设置线程的名字
- (void)setName:(NSString *)name;
- (NSString *)name;
获得当前线程
[NSThread currentThread];
线程调度优先级:优先级范围在0.0~1.0之间,默认是0.5,值越大,优先级越高,越容易被调度。
- (void)setThreadPriority:(double)priority
- (double)threadPriority
主线程
+ (NSThread *)mainThread; // 获得主线程
- (BOOL)isMainThread; // 是否为主线程
+ (BOOL)isMainThread; // 是否为主线程
1.线程的创建
1>NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(callback) object:nil];
[thread start];
2>[NSThread detachNewThreadSelector:@selector(callback:) toTarget:self withObject:nil];
3>[self performSelectorInBackground:@selector(callback:) withObject:nil];
第一种相比较后两种而言可以更加精准的控制线程相关设置,比如线程名称,优先级等。
2.线程的状态
新建:线程创建出来
就绪:调用线程start方法,加载到线程池等待调度
运行:线程得到cpu调度
阻塞:线程睡眠或等待同步锁
死亡:线程执行完毕或者强制退出或者程序崩溃
3.线程的同步
当多个线程访问共享资源时,会有数据安全问题,例如写出错,读取脏数据,解决办法是加互斥锁。
//加锁
@synchronized(self){
访问共享资源代码
}//解锁
4.线程的通信
有时候多个线程之间需要相互通信,互相传递数据,比如在子线程下载好图片资源后需要回到主线程更新UI界面
可以在子线程内部发发异步请求向主线程传递数据。
- (void)threadCommunicate
{
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(download) object:nil];
[thread setThreadPriority:1];
thread.name = @"线程A";
[thread start];
}
- (void)download
{
//1.下载图片
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://su.bdimg.com/static/superplus/img/logo_white_ee663702.png"]];
UIImage *image = [UIImage imageWithData:data];
//2.更新图片(子线程下载的图片返回给主线程更新UI界面)
[self.imageView performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:NO];
}
2.GCD(Grand Central Dispatch)
GCD会充分利用设备的多核技术,自动管理线程的生命周期,程序员只需要将任务放在相关队列中就可以了,不用关心线程的状态
首先理解两个概念
队列:
串行队列:队列的任务串行执行
并发队列:队列的任务并发执行
请求:
同步:不会开启新线程
异步:会开启新线程,只有放在并发队列中才会实现多线程技术,放在串行队列中只会开启一个线程且任务串行执行。
- (void)viewDidLoad { [super viewDidLoad]; //1.串行队列(队列里面的操作串行执行) self.serialQueue = dispatch_queue_create("串行对列",DISPATCH_QUEUE_SERIAL); //2.并发队列(队列里面的操作并发执行) self.concurrentQueue = dispatch_queue_create("并行队列",DISPATCH_QUEUE_CONCURRENT); //3.全局队列(系统自带并发队列) self.globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); //4.主队列(与主线程相关) self.mainQueue = dispatch_get_main_queue(); NSLog(@"主线程%@",[NSThread currentThread]); //[self gcdCommunicate]; } /** * 同步函数dispatch_sync不会开启新线程 */ - (void)sync { //在串行队列中同步执行操作 for(int i = 0;i<10;i++){ dispatch_sync(self.serialQueue, ^{ NSLog(@"同步串行%@--%d",[NSThread currentThread],i); }); } //在并发队列中同步执行操作 for(int i = 0;i<10;i++){ dispatch_sync(self.concurrentQueue, ^{ NSLog(@"同步并发%@",[NSThread currentThread]); }); } //在全局队列中同步执行操作 for(int i = 0;i<10;i++){ dispatch_sync(self.globalQueue, ^{ NSLog(@"同步全局%@",[NSThread currentThread]); }); } //在主队列中同步执行操作 #warning 在主线程中执行同步操作会卡住 dispatch_sync(self.mainQueue, ^{ NSLog(@"同步主%@",[NSThread currentThread]); }); } /** * 异步函数dispatch_async会开启新线程 */ - (void)async { //在串行队列中异步执行操作(开启一条子线程,操作串行执行) for(int i = 0;i<10;i++){ dispatch_async(self.serialQueue, ^{ NSLog(@"异步串行%@---%d",[NSThread currentThread],i); }); } //在并发队列中异步执行操作(开启多条子线程,操作并发执行) for(int i = 0;i<10;i++){ dispatch_async(self.concurrentQueue, ^{ NSLog(@"异步并发%@---%d",[NSThread currentThread],i); }); } //在全局队列中异步执行操作(开启多条子线程,操作并发执行) for(int i = 0;i<10;i++){ dispatch_async(self.globalQueue, ^{ NSLog(@"异步全局%@---%d",[NSThread currentThread],i); }); } //在主队列中异步执行操作(在主线程上执行,操作串行执行) for(int i = 0;i<10;i++){ dispatch_async(self.globalQueue, ^{ NSLog(@"异步主%@---%d",[NSThread currentThread],i); }); } } /** * GCD的线程通信 */ - (void)gcdCommunicate { dispatch_async(self.globalQueue, ^{ NSLog(@"当前线程%@", [NSThread currentThread]); // 下载图片 NSURL *url = [NSURL URLWithString:@"http://news.baidu.com/z/resource/r/image/2014-06-22/2a1009253cf9fc7c97893a4f0fe3a7b1.jpg"]; NSData *data = [NSData dataWithContentsOfURL:url]; UIImage *image = [UIImage imageWithData:data]; // 回到主线程显示图片 dispatch_async(self.mainQueue, ^{ NSLog(@"当前线程%@", [NSThread currentThread]); self.imageView.image = image; }); }); }
3.NSOperation
NSOperation底层基于GCD,使用OC编写,更加面向对象,是苹果官方比较推荐的技术
配合使用NSOperation和NSOperationQueue也能实现多线程编程
1>使用步骤
首先创建NSOperation对象,将操作封装到里面
然后将NSOperation对象添加到NSOperationQueue中
系统会自动将NSOperation中封装的操作放到一条新线程中执行
2>子类
NSOperation是个抽象类,并不具备封装操作的能力,必须使用它的子类
使用NSOperation子类的方式有3种
NSInvocationOperation
NSBlockOperation
自定义子类继承NSOperation,实现内部相应的方法
/** * NSInvocationOperation的使用 */ - (void)invocationOperation { // 1.创建操作对象, 封装要执行的操作 NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(callback) object:nil]; // 2.启动操作(默认情况下,如果操作没有放到队列queue中,都是同步执行) [operation start]; } - (void)callback { NSLog(@"当前线程%@",[NSThread currentThread]); } /** * NSBlockOperation的使用 */ - (void)blockOperation { // 1.创建操作对象, 封装要执行的操作 NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"当前线程%@--操作1",[NSThread currentThread]); }]; [operation addExecutionBlock:^{ NSLog(@"当前线程%@--操作2",[NSThread currentThread]); }]; [operation addExecutionBlock:^{ NSLog(@"当前线程%@--操作3",[NSThread currentThread]); }]; //监听操作 operation.completionBlock = ^(){ NSLog(@"当前线程%@--操作完毕", [NSThread currentThread]); }; // 2.启动操作(如果只有一个操作不会开启线程,如果有多个操作,就会开启新线程) [operation start]; } /** * NSOperationQueue的使用 */ - (void)OperationQueue { //1.创建操作队列 NSOperationQueue *queue = [[NSOperationQueue alloc] init]; //设置队列的最大并发数 queue.maxConcurrentOperationCount = 3; //2.创建操作 NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"当前线程%@-操作1",[NSThread currentThread]); }]; NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"当前线程%@-操作2",[NSThread currentThread]); }]; NSInvocationOperation *operation3 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(invocation) object:nil]; //设置依赖 //[operation2 addDependency:operation1]; //[operation3 addDependency:operation2]; //3.操作放在队列中 [queue addOperation:operation1]; [queue addOperation:operation2]; [queue addOperation:operation3]; } - (void)invocation { NSLog(@"当前线程%@-操作3",[NSThread currentThread]); }
//写的有点晚了,本来想写细点,不过感觉这些代码和思想都很简单,方便以后自己重温就行了,所以写的糙了点,海涵。