Fork me on GitHub

pthread、NSThread、GCD、NSOperation、NSOperationQueue

pthread、NSThread

GCD

基本介绍

1
2
3
4
5
6
7
8
9
10
11
12
13
// 并发队列
dispatch_queue_t queue_t = dispatch_queue_create("ccc", DISPATCH_QUEUE_CONCURRENT);
// 串行队列
dispatch_queue_t queue_t1 = dispatch_queue_create("ccc", DISPATCH_QUEUE_SERIAL);
// 串行队列 (主队列)
dispatch_get_main_queue();
// 全局并发队列
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

// 同步
dispatch_sync
// 异步
dispatch_async

线程通讯

1
2
3
4
// gcd 线程通讯一般只有 子线程通讯到主线程,
// 因为我们在处理gcd的时候没有操作具体的线程,
// 全部是由系统来处理的
dispatch_async(mainQueue, ^{

延时操作

1
2
// 延时操作 这里只是延时把任务加到队列中,具体什么时候执行是未知的。
// dispatch_after

只执行一次

1
2
// 只执行一次
dispatch_once(&onceToken, ^{

快速迭代方法

1
2
3
// 快速迭代方法,普通遍历数组的时候是一个一个取,
// 如果用快速迭代的话就可以在多个线程中同时(异步)遍历。
dispatch_apply(6, queue, ^(size_t index) {

栅栏

1
2
3
4
5
6
7
// 栅栏 可以把任务栅起来特殊处理,指定哪些任务完成后在执行哪些任务
// 1 2 完成了再继续这些 3 4 5任务
dispatch_async(queue, ^{
dispatch_async(queue, ^{
dispatch_barrier_async(queue, ^{
dispatch_async(queue, ^{
dispatch_async(queue, ^{

队列组

###通知方式

1
2
3
4
// 1 2 完成才通知 3
dispatch_group_async(grou
dispatch_group_async(grou
dispatch_group_notify(grou

堵塞

1
2
3
4
5
// 暂停方式 
// 到3就暂停堵塞当前线程,当 1 2 完成后才解除暂停
dispatch_group_async(grou
dispatch_group_async(grou
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

### 标记的方式

// 使用标记的方式
// 标记开始一个,标记结束一个
dispatch_group_enter(group);
dispatch_async(queue, ^{
dispatch_group_leave(group);
});

dispatch_group_enter(group);
dispatch_async(queue, ^{
dispatch_group_leave(group);
});

dispatch_group_notify(group, dispatch_get_main_queue(), ^{
});

信号量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 信号量 Dispatch Semaphore 线程同步,将异步执行任务转换为同步执行任务。

Dispatch Semaphore 提供了三个方法:
dispatch_semaphore_create:创建一个 Semaphore 并初始化信号的总量
dispatch_semaphore_signal:发送一个信号,让信号总量加 1
dispatch_semaphore_wait:可以使总信号量减 1,信号总量小于 0 时就会一直等待(阻塞所在线程),否则就可以正常执行。

// 全局并发队列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// maphore 初始创建时计数为 0。
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
dispatch_async(queue, ^{
// 发送一个信号,让信号总量加 1
dispatch_semaphore_signal(semaphore);
});
// 到这里让信号量减 1 、是-1 小于0 就开始等待,当信号量是0 或者大于1 时就继续执行
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);

NSLog(@"任务完成了");

NSOperation、NSOperationQueue

NSOperation、NSOperationQueue 是苹果提供给我们的一套多线程解决方案。实际上 NSOperation、NSOperationQueue 是基于 GCD 更高一层的封装,完全面向对象。但是比 GCD 更简单易用、代码可读性也更高。

为什么要使用 NSOperation、NSOperationQueue?

  • 可添加完成的代码块,在操作完成后执行。

  • 设定操作执行的优先级。

  • 可以很方便的取消一个操作的执行。

  • 使用 KVO 观察对操作执行状态的更改:isExecuteing、isFinished、isCancelled。

创建操作

NSOperation 的创建

NSInvocationOperation

1
2
3
4
5
// 在当前线程上执行
// 1.创建 NSInvocationOperation 对象
NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(task1) object:nil];
// 2.调用 start 方法开始执行操作
[op start];

NSBlockOperation

1
2
3
4
5
6
7
8
9
10
// 各种 Block 可以在多个线程上执行
// 1.创建 NSBlockOperation 对象
NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:
// 2.添加额外的操作
[op addExecutionBlock:
[op addExecutionBlock:
[op addExecutionBlock:
[op addExecutionBlock:
// 3.调用 start 方法开始执行操作
[op start];

NSOperation 自定义

1
2
自定义 NSOperation 的方式暂时不考虑
@interface YSCOperation : NSOperation

NSOperationQueue 操作队列

创建 Queue

1
2
3
4
5
6
// 获取主队列
[NSOperationQueue mainQueue];
// 获取当前队列
[NSOperationQueue currentQueue];
// 创建自定义队列 (可以通过其他属性来确定是串行或者并发 maxConcurrentOperationCount)
[[NSOperationQueue alloc] init];

向 NSOperationQueue 中添加操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 在 Queue 直接添加操作  不需要调用 NSOperation 的 start 方法 
// 1.创建队列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];

// 2.创建操作
// 使用 NSInvocationOperation 创建操作1
NSInvocationOperation *op1 = [[NSInvocationOperation alloc] initWithTarget:self
NSInvocationOperation *op2 = [[NSInvocationOperation alloc] initWithTarget:self

NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
[op3 addExecutionBlock:

// 3.使用 addOperation: 添加所有操作到队列中
[queue addOperation:op1];
[queue addOperation:op2];
[queue addOperation:op3];

向 Queue 中直接加 Block 的方式

1
2
3
4
5
6
// 1.创建队列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
// 2.使用 addOperationWithBlock: 添加操作到队列中
[queue addOperationWithBlock:
[queue addOperationWithBlock:
[queue addOperationWithBlock:

控制并发和串行 maxConcurrentOperationCount

1
2
3
4
// 默认 -1 不控制
// 1 串行
// n 并发,但不会超过系统限制
@property NSInteger maxConcurrentOperationCount;

NSOperation 的依耐和优先级

依耐

NSOperation 的一个特点就是可以添加各种操作依赖,同时还可以设置一下参数,取消,暂停,恢复等。

1
2
3
4
// 依赖确定了谁在前执行和谁在后执行。(a的执行需要b执行完毕,a依耐b)
- (void)addDependency:(NSOperation *)op;
- (void)removeDependency:(NSOperation *)op;
@property (readonly, copy) NSArray<NSOperation *> *dependencies;

优先级

1
2
// 都处于就绪的状态的任务(操作),谁先开始执行,谁先取到。
@property NSOperationQueuePriority queuePriority;

线程间的通信

1
2
3
4
5
6
7
8
9
10
// 1.创建队列
NSOperationQueue *queue = [[NSOperationQueue alloc]init];

// 2.添加操作
[queue addOperationWithBlock:^{
// 异步进行耗时操作
// 回到主线程
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
}];
}];

常用属性和方法归纳

NSOperation

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 取消操作方法
- (void)cancel; 可取消操作,实质是标记 isCancelled 状态。

// 判断操作状态方法
- (BOOL)isFinished; 判断操作是否已经结束。
- (BOOL)isCancelled; 判断操作是否已经标记为取消。
- (BOOL)isExecuting; 判断操作是否正在在运行。
- (BOOL)isReady; 判断操作是否处于准备就绪状态,这个值和操作的依赖关系相关。
操作同步
- (void)waitUntilFinished; 阻塞当前线程,直到该操作结束。可用于线程执行顺序的同步。
- (void)setCompletionBlock:(void (^)(void))block; completionBlock 会在当前操作执行完毕时执行 completionBlock。
- (void)addDependency:(NSOperation *)op; 添加依赖,使当前操作依赖于操作 op 的完成。
- (void)removeDependency:(NSOperation *)op; 移除依赖,取消当前操作对操作 op 的依赖。
@property (readonly, copy) NSArray<NSOperation *> *dependencies; 在当前操作开始执行之前完成执行的所有操作对象数组。

NSOperationQueue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
取消/暂停/恢复操作
- (void)cancelAllOperations; 可以取消队列的所有操作。
- (BOOL)isSuspended; 判断队列是否处于暂停状态。 YES 为暂停状态,NO 为恢复状态。
- (void)setSuspended:(BOOL)b; 可设置操作的暂停和恢复,YES 代表暂停队列,NO 代表恢复队列。
操作同步
- (void)waitUntilAllOperationsAreFinished; 阻塞当前线程,直到队列中的操作全部执行完毕。
添加/获取操作`
- (void)addOperationWithBlock:(void (^)(void))block; 向队列中添加一个 NSBlockOperation 类型操作对象。
- (void)addOperations:(NSArray *)ops waitUntilFinished:(BOOL)wait; 向队列中添加操作数组,wait 标志是否阻塞当前线程直到所有操作结束
- (NSArray *)operations; 当前在队列中的操作数组(某个操作执行结束后会自动从这个数组清除)。
- (NSUInteger)operationCount; 当前队列中的操作数。
获取队列
+ (id)currentQueue; 获取当前队列,如果当前线程不是在 NSOperationQueue 上运行则返回 nil
+ (id)mainQueue; 获取主队列。
- END -
扫一扫上面的二维码图案,加我微信

文章作者:梁大红

特别声明:若无特殊声明均为原创,转载请注明,侵权请联系

版权声明:署名-非商业性使用-禁止演绎 4.0 国际