iOS开发-多线程知识点
一. NSThread 面向对象的,需要程序员手动创建线程,但不需要手动销毁。子线程间通信很难.
1.创建子线程,再启动:
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(testThread:) object:@"参数"];//有返回值,可以拿到返回值设置线程的优先级和名称
[thread start];//需要手动开启
2.创建并自动启动:
[NSThread detachNewThreadSelector:@selector(testThread:) toTarget:self withObject:@"便利构造器方式"];//没有返回值,不需要手动开启
3.使用 NSObject 的方法创建并自动启动:
[self performSelectorInBackground:@selector(run:)withObject:@"开启后台线程"];//没有返回值,不需要手动开启,只要是NSObject对象或者是NSObject的子类对象都可以用这种方法开启子线程,
4.回到主线程的方法:
[self performSelectorOnMainThread:@selector(backMainThread) withObject:nil waitUntilDone:YES];
二. GCD - Grand Central Dispatch (任务 和 队列)
1.基本概念:
@1. 自动管理线程的生命周期(创建线程、调度任务、销毁线程);
@2. 同步(sync) 和 异步(async) 的主要区别在于会不会阻塞当前线程,直到 Block 中的任务执行完毕!
如果是 同步(sync) 操作,它会阻塞当前线程并等待 Block 中的任务执行完毕,然后当前线程才会继续往下运行; 如果是果是果是异步(async)操作,当前线程会直接往下执行,它不会阻塞当前线程。
2.同步任务会阻塞当前线程,然后把 Block 中的任务放到指定的队列中执行,只有等到 Block 中的任务完成后才会让当前线程继续往下运行。
NSLog("之前 - %@", NSThread.currentThread());
dispatch_sync(dispatch_get_main_queue(), { () -> Void in
NSLog("sync - %@", NSThread.currentThread());
});
NSLog("之后 - %@", NSThread.currentThread());
结果:只会打印第一句:之前 - <NSThread: 0x7fb3a9e16470>{number = 1, name = main} ,然后主线程就卡死了
3.队列组
//1.创建队列组
dispatch_group_t group = dispatch_group_create();
//2.创建队列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//3.多次使用队列组的方法执行任务, 只有异步方法
//3.1.执行3次循环
dispatch_group_async(group, queue, ^{
for (NSInteger i = 0; i < 3; i++) {
NSLog(@"group-01 - %@", [NSThread currentThread]);
}
});
//3.2.主队列执行8次循环
dispatch_group_async(group, dispatch_get_main_queue(), ^{
for (NSInteger i = 0; i < 8; i++) {
NSLog(@"group-02 - %@", [NSThread currentThread]);
}
});
//4.都完成后会自动通知
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"完成 - %@", [NSThread currentThread]);
});
4.回到主线程的方法:
dispatch_async(dispatch_get_main_queue(), ^{
});
三. NSOperation 基于GCD封装,完全面向对象.
1.将要执行的任务封装到一个 NSOperation 对象中。将此任务添加到一个 NSOperationQueue 对象中。
NSOperation 只是一个抽象类,所以不能封装任务。但它有 2 个子类用于封装任务。分别是:NSInvocationOperation 和 NSBlockOperation 。创建一个 Operation 后,需要调用 start 方法来启动任务,它会 默认在当前队列同步执行
@1.创建NSInvocationOperation对象
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run) object:nil];
//开始执行
[operation start];
@2.创建NSBlockOperation对象
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"%@", [NSThread currentThread]);
}];
//添加多个Block (NOTE:addExecutionBlock 方法必须在 start() 方法之前执行,否则就会报错:)
for (NSInteger i = 0; i < 5; i++) {
[operation addExecutionBlock:^{
NSLog(@"第%ld次:%@", i, [NSThread currentThread]);
}];
}
//开始任务
[operation start];
2. 创建队列
@1. 主队列
NSOperationQueue *queue = [NSOperationQueue mainQueue];
@2. 其他队列
//1.创建一个其他队列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
//2.创建NSBlockOperation对象
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"%@", [NSThread currentThread]);
}];
//3.添加多个Block
for (NSInteger i = 0; i < 5; i++) {
[operation addExecutionBlock:^{
NSLog(@"第%ld次:%@", i, [NSThread currentThread]);
}];
}
//4.队列添加任务
[queue addOperation:operation];
3. NSOperationQueue 有一个参数 maxConcurrentOperationCount 最大并发数,用来设置最多可以让多少个任务同时执行。当你把它设置为 1 的时候,就是串行了嘛!
NSOperationQueue 还有一个添加任务的方法,- (void)addOperationWithBlock:(void (^)(void))block;
4.回到主线程的方法:
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
}];
四. iOS多线程对比
1. NSThread
1)优点:轻量级,建立一个线程非常方便。
2)缺点:需要手动管理所有的线程活动, 管理多个线程非常困难。
2. NSOperation
1)优点:自带线程周期管理,操作上可更注重自己逻辑; 可以监听任务执行状态,取消任务,限制最大并发数量。
2)缺点:面向对象的抽象类,只能实现它或者使用它定义好的两个子类:NSInvocationOperation 和 NSBlockOperation。
3. GCD 一个多核编程的解决方法。
1)优点:用Block定义任务,使用起来非常灵活便捷;提供了更多的控制能力以及操作队列中所不能使用的底层函数;最高效,避开并发陷阱。
2)缺点:是基于C语言的底层API。
4. 选择小结
1)简单而安全的选择NSOperation实现多线程即可。
2)处理大量并发数据,又追求性能效率的选择GCD。
特别鸣谢大神提供参考与转载链接:
2. 谈iOS多线程(NSThread、NSOperation、GCD)编程 - CocoaChina_一站式开发者成长社区