概述
优点:
- 把程序中耗时的任务放到后台去处理,如图片、视频的下载等;
- 充分发挥多核处理器的优势,并发执行让系统运行的更快、更流畅、用户体验更佳。
不足:
- 大量的线程操作会降低代码的可读性;
- 大量的线程需要更多的内存空间;
- 当多个线程对同一资源出现争夺的时候会出现线程安全问题。
目前实现多线程的技术有四种:pthread、NSThread、GCD和NSOperation。
- pthread:是一套基于C语言的通用多线程API,线程的生命周期需要我们手动管理,使用难度较大,所以我们几乎不会使用。
- NSThread:是一套面向对象的API,线程的生命周期需要我们手动管理,简单易用,可直接操作线程对象。
- GCD:是一套底层基于C语言的多线程API,自动管理生命周期,充分利用了多核处理器的优点。
- NSOperation:是一套底层基于GCD面向对象的多线程API,自动管理生命周期,并且比GCD多了一些更简单实用的功能。
在这里我们暂且不讨论pthread的使用,主要看看后面三个方案都是怎么应用的。
NSThread
一个NSThread对象就代表一个线程,使用NSThread有多种创建线程的方式:
1. 先创建再启动
// 创建
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run:) object:@"Axe"];
// 启动
[thread start];
2. 直接创建并启动线程
[NSThread detachNewThreadSelector:@selector(run:) toTarget:self withObject:@"Axe"];
3. 创建并启动
[self performSelectorInBackground:@selector(run:) withObject:@"Axe"];
[NSThread sleepForTimeInterval:2.0];
从三种创建线程的方法可以看到:方法2和3都可以更方便的创建一个线程,并且自启动。而方法一可以很方便的拿到线程对象。
4.应用示例
以下载一张图片为例:
NSURL *url = [NSURL URLWithString:@"http://f.hiphotos.baidu.com/image/pic/item/203fb80e7bec54e753da379aba389b504fc26a7b.jpg"];
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(downloadImageWithURL:) object:url];
[thread start];
- (void)downloadImageWithURL:(NSURL *)url {
NSError *error;
NSData *data = [NSData dataWithContentsOfURL:url options:NSDataReadingMappedIfSafe error:&error];
if (error) {
NSLog(@"error = %@",error);
} else {
UIImage *image = [UIImage imageWithData:data];
[self.imageView performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:YES];
}
}
GCD
GCD全称是Grand Central Dispatch,可译为“
中枢调度器”。GCD是苹果公司为多核的并行运算提出的解决方案,它会自动利用更多的CPU内核来开启线程执行任务。
在了解GCD之前先明白同步/异步、并行/串行这几个名词的概念。
- 同步线程:在当前线程可立即执行任务,不具备开启线程的能力,会阻塞当前的线程,必须等待同步线程中的任务执行完并返回后,才会执行下一个任务。
- 异步线程:在当前线程结束后执行任务,具备开启新的线程的能力。
- 并行队列:允许多个任务同时执行。
- 串行队列:只有等上一个任务执行完毕后,下一个任务才会被执行。
创建串行队列
dispatch_queue_t serialQueue = dispatch_queue_create("com.serial.queue", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t mainQueue = dispatch_get_main_queue();
创建并行队列
dispatch_queue_t concurrentQueue = dispatch_queue_create("com.concurrent.queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
创建同步+串行队列
//在当前线程,立即执行任务
dispatch_queue_t serialQueue = dispatch_queue_create("com.serial.queue", DISPATCH_QUEUE_SERIAL);
dispatch_sync(seria