一、多线程概述
1、程序,进程,线程
- 程序:由源代码生成的可执行应用。(例如:QQ.app)
- 进程:一个正在运行的程序可以看做一个进程。(例如:正在运行的QQ就是一个进程),进程拥有独立运行所需的全部资源。
- 线程:程序中独立运行的代码段。(例如:接收QQ消息的代码)
- 一个进程是由一或多个线程组成。进程只负责资源的调度和分配,线程才是程序真正的执行单元,负责代码的执行。
2、单线程
- 每个正在运行的程序(即进程),至少包含一个线程,这个线程叫主线程。
- 主线程在程序启动时被创建,用于执行main函数。
- 只有一个主线程的程序,称作单线程程序。
- 在单线程程序中,主线程负责执行程序的所有代码(UI展现以及刷新,网络请求,本地存储等等)。这些代码只能顺序执行,无法并发执行。
3、多线程
- 拥有多个线程的程序,称作多线程程序。
- iOS允许用户自己开辟新的线程,相对于主线程来讲,这些线程,称作子线程。
- 可以根据需要开辟若干子线程
- 子线程和主线程 都是 独立的运行单元,各自的执行互不影响,因此能够并发执行。
4、单,多线程的区别
- 单线程程序:只有一个线程,即主线程,代码顺序执行,容易出现代码阻塞(页面假死)。
- 多线程程序:有多个线程,线程间独立运行,能有效的避免代码阻塞,并且提高程序的运行性能。
- 注意:iOS中关于UI的添加和刷新必须在主线程中操作。
二、NSThread
实现多线程方式之一:NSThread,它是一个轻量级的多线程。它有以下两种创建方法:
#pragma mark - NSThread手动开辟子线程
// 参数1:target
// 参数2:方法
// 参数3:传参
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(sayHi) object:nil];
[thread start];
// 使用NSThread和NSObject实现的开辟线程,系统会自动释放,所以不需要自己手动关闭。
// 结束线程的两种方式
// 取消线程(给线程发送结束消息,通过这个消息进行取消)
[thread cancel];
// 立即结束线程
[NSThread exit];
#pragma mark - NSThread自动开辟子线程
// 线程自动开始
// 把手动开启的target和selector顺序颠倒
[NSThread detachNewThreadSelector:@selector(sayHi) toTarget:self withObject:nil];
// 获取当前线程
NSLog(@"current == %@", [NSThread currentThread]);
// 获取主线程
NSLog(@"mainThread == %@", [NSThread mainThread]);
// 判断当前线程是否为主线程
NSLog(@"isMainThread == %d", [NSThread isMainThread]);
NSObject中存在了一个最简单的后台执行的方法:
#pragma mark - NSObject开启子线程
/**
* 开启子线程的方式之一:NSObject
*/
// 使用performSelectorInBackground开辟子线程
// 第一个参数:selector
// 第二个参数:方法传递的参数
[self performSelectorInBackground:@selector(sayHi) withObject:@"test"];
- (void)sayHi
{
// 回到主线程
// 参数1:selector
// 参数2:传参
// 参数3:是否等待子线程完成之后进入主线程
[self performSelectorOnMainThread:@selector(mainThreadChangeColor) withObject:nil waitUntilDone:YES];
}
三、NSOperationQueue
1、NSOperation
- NSOperation类,在MVC中属于M,是用来封装单个任务相关的代码和数据的抽象类。
- 因为它是抽象的,不能够直接使用这个类,而是使用子类( NSInvocationOperation或NSBlockOperation )来执行实际任务。
- NSOperation(含子类),只是一个操作,本身无主线程、子线程之分,可在任意线程中使用。通常与NSOperationQueue结合使用。
- 注意:在使用NSOperation的子类去创建线程的时候,实际线程没有真正意义上的创建。
2、NSInvocationOperation
- NSInvocationOperation是NSOperation的子类
- 封装了执行操作的target和要执行的action。
/**
* NSOperation不能直接进行多线程的创建,需要借助:NSOperationQueue
*/
// 使用NSOperation的第一个子类去创建子线程:NSInvocationOperation
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(test) object:nil];
// 在单独使用NSOperation的子类去创建线程的时候,一定要启动才行
[operation start];
3、NSBlockOperation
- NSBlockOperation是NSOperation的子类
- 封装了需要执行的代码块
//使用NSOperation的第二个子类创建子线程
NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"我是block");
NSLog(@"-------%@", [NSThread currentThread]);
NSLog(@"********%@", [NSThread mainThread]);
}];
[blockOperation start];
- 需要把上边的两个线程,放到操作队列里,才是真正意义上的创建子进程
- addOperation一旦将创建的对象加入到操作队列中,就不能调用start方法,否则程序会crash
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperation:operation];
[queue addOperation:blockOperation];
4、NSOperationQueue
- NSOperationQueue是操作队列,他用来管理一组Operation对象的执行,会根据需