文章目录
  1. 1. 使用NSCondition控制NSThread线程通信
  2. 2. 同步/异步 与 串行/并行
  3. 3. 线程同步
  4. 4. 延迟执行
  5. 5. 从其他线程放到主线程执行
  6. 6. 重写NSOpeation子类

重点参考自 关于iOS多线程,你看我就够了。 这里只对关键的点做一总结。

iOS提供4种多线程方式:Pthreads\NSThread\Grand Central Dispatch(GCD)\NSOperation

其封装性、OO性依次由低到高。

NSThread线程的几种状态: 新建状态,就绪状态(调用start后,并不马上执行,而需等待系统真正调用),运行状态,阻塞状态(sleep),停止状态。

使用NSCondition控制NSThread线程通信

NSCondition类(充当信号量)提供了如下3种方法:

  • wait: 该方法导致当前线程一直等待,直到其他线程调用该NSCondition的signal方法或broadcast方法唤醒该线程。 wait方法的一个变体:- (BOOL)waitUntilData:,用于控制的等待的时间点;
  • signal: 唤醒在此NSCondition对象上等待的单个线程。如果所有线程都在该NSCondition对象上等待,则会任意选择唤醒其中一个线程。只有当前线程使用wait方法后,才可以执行被唤醒;
  • broadcast: 唤醒在此NSCondition对象等待的所有线程。只有当前线程使用wait方法后,才可以执行被唤醒。

NSCondition调用方法前需要加锁,防止被同步篡改。

NSOperation对比GCD的好处是可以方便地cancel。还可以自定义NSOperation子类,实现 main, cancel.; NSOperationQueue中的NSOperation可以设置依赖(先后)关系。

同步/异步 与 串行/并行

  • 如果是 同步(sync) 操作,它会阻塞当前线程并等待 Block 中的任务执行完毕,然后当前线程才会继续往下运行,因此没有使用其他线程。

  • 如果是 异步(async)操作,当前线程会直接往下执行,它不会阻塞当前线程,因此会使用其他线程。

  • 串行队列:放到串行队列的任务,GCD 会 FIFO(先进先出) 地取出来一个,执行一个,然后取下一个,这样一个一个的执行。

  • 并行队列:放到并行队列的任务,GCD 也会 FIFO的取出来,但不同的是,它取出来一个就会放到别的线程,然后再取出来一个又放到另一个的线程。这样由于取的动作很快,忽略不计,看起来,所有的任务都是一起执行的。不过需要注意,GCD 会根据系统资源控制并行的数量,所以如果任务很多,它并不会让所有任务同时执行。

同步执行(只用当前线程) 异步执行 (只用其他线程)
串行队列 当前线程,一个一个依次执行 其他线程,一个一个依次执行
并行队列 当前线程,一个一个依次执行 开很多线程,一起执行
  • dipatch_apply: 异步 多次执行同一个代码块
  • dipatch_once: 用主线程执行代码块一次

线程同步

所谓线程同步就是为了防止多个线程抢夺同一个资源造成的数据安全问题,所采取的一种措施。有如下2种方法:

  • 互斥锁
    给需要同步的代码块加一个互斥锁,就可以保证每次只有一个线程访问此代码块:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 方法一: @synchronized(){} 自动加锁
@synchorinized(self) {
// 需要执行的代码块
}
// 方法二:手动加NSLock
NSLock* lock;
[lock lock]; // 加锁
// 需要执行的代码块
...
[lock unlock]; // 释放
// 方法三:手动加OSSPinLock锁
// 1. 定义一个自旋锁property
OSSpinLock _storelock; // 需 #import <libkern/OSAtomic.h>
// 2. 使用
OSSpinLockLock(&_storelock);
// 需要执行的代码块
...
OSSpinLockUnlock(&_storelock);
  • 同步执行
    把多个线程都要执行的代码块添加到同一个串行队列,这样就防止了资源的抢夺。

GCD

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 1. 通过一个全局的单例对象MyQueueManager,提供一个全局的串行队列globalSearialQueue
static MyQueueManager* _instance;
+ MyQueueManager* shareInstance {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [[MyQueueManager alloc] init];
});
return _instance;
}
- (dispatch_queue_t) globalSerialQueue {
if (_globalSerialQueue == nil) {
_globalSerialQueue = dispatch_queue_create("GlobalSearialQueue", DISPATCH_QUEUE_SERIAL);
}
return _globalSerialQueue;
}
// 2. 使用该queue,加入dispatch_sync同步代码块
dispatch_queue_t queue = [MyQueueManager shareInstance].globalSearialQueue;
dispatch_sync(queue, ^{
// 需要执行的代码块
...
});

NSOperation

1
2
3
4
5
6
7
8
9
// 1. 同样生成一个全局的NSOperationQueue,其最大并发数 maxConcurrentOperationCount = 1, 用来将所有操作都添加到这个queue中
... 略
// 2. 加入operation到queue中
NSBlockOperation* operation = [NSBlockOperation blockOperationWithBlock:^{
// 需要执行的代码块
}];
[queue addOperation:operation];
// 3. 如果后续操作需要operation中的block的结果,可以调用
[operation waitUntilFinished]; // 阻塞当前线程直至完成

延迟执行

所谓延迟执行就是延时一段时间再执行某段代码。有如下3种方式:

  • perform
    [self preformSelector:@selector(run:) withObject@"abc" afterDelay:3]; // 延迟3s

  • GCD

1
2
3
4
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,(int64_t)( 3* NSEC_PER_SEC)), queue ^{
// 需要执行的代码
} );
  • NSTimer
1
2
3
4
5
6
7
// 该timer会被自动添加到当前的run loop中,并在指定的3s后发送run:消息到self,完成方法调用
[NSTimer scheduledTimerWithTimeInterval: 3.0 target:self selector:@selector(run:) userInfo:@"abc" repeats:NO];
// 或者
NSTimer* timer = [NSTimer timerWithTimeInterval: 3.0 target:self selector:@selector(run:) userInfo:@"abc" repeats:NO];
NSRunLoop* runner = [NSRunLoop currentRunLoop];
runner addTimer:timer forMode: NSDefaultRunLoopMode];
[timer fire]; //手动开始计时

从其他线程放到主线程执行

主要有3种:

  • NSThread
1
[self performSelectorOnMainThread:@selector(run:) withObject:@"aaa" waitUntilDoen:NO];
  • GCD
1
2
3
4
5
6
7
8
9
10
dispatch_async(dispatch_get_main_queue(), ^{
....
});
* NSOperation
```objc
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
....
}];

重写NSOpeation子类

重写NSOperation的main方法即可。

文章目录
  1. 1. 使用NSCondition控制NSThread线程通信
  2. 2. 同步/异步 与 串行/并行
  3. 3. 线程同步
  4. 4. 延迟执行
  5. 5. 从其他线程放到主线程执行
  6. 6. 重写NSOpeation子类