Objective-C 中实现多线程

在多核 CPU 时代,由于硬件上就支持多线程技术,就可以让多个线程真正同时地运行。如果任务能够被拆分,各个子任务就能并行地在 CPU 上运行,这就能显著加快运行速度。

performSelectors

NSObject 提供了以 performSelector 为前缀的一系列方法。它们可以让用户在指定线程中,或者立即,或者延迟执行某个方法调用。

- (void)performSelector:(SEL)aSelector
- (void)performSelector:(SEL)aSelector withObject:(id)anArgument
- (void)performSelector:(SEL)aSelector withObject:(id)anArgument withObject:(id)anArgument
- (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(NSTimeInterval)delay
- (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay: (NSTimeInterval)delay inModes:(NSArray *)modes

// 在指定线程中执行方法
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thread withObject:(id)arg waitUntilDone:(BOOL)wait
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thread withObject: (id)arg waitUntilDone:(BOOL)wait modes:(NSArray *)array
// 在主线程中执行方法
- (void)performSelectorOnMainThread: (SEL)selector withObject:(id)argument waitUntilDone:(BOOL)wait
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait modes:(NSArray *)array

// 在后台线程中执行方法
- (void)performSelectorInBackground:(SEL)aSelector withObject:(id)arg

这一系列方法简单易用:指定执行的方法(但传入方法的参数数量有限制);指定是在当前线程,还是在主线程,还是在后台线程执行;指定是否需要阻塞当前线程等待结果。

NSThread

NSThread 是 OS X 和 iOS 都提供的一个线程对象,它是线程的一个轻量级实现。在执行一些轻量级的简单任务时,NSThread 很有用,但用户仍然需要自己管理线程生命周期,进行线程间同步。比如,线程状态,依赖性,线程间同步等线程相关的主题 NSThread 都没有涉及。比如,涉及到线程间同步仍然需要配合使用 NSLock,NSCondition 或者 @synchronized。所以,遇到复杂任务时,轻量级的 NSThread 可能并不合适。

- (void)run {
    while (TRUE) {
        [_lock lock];
        if(_cake > 0){
            [NSThread sleepForTimeInterval:0.5];
            _cake--;
            _occupied = kSum - _cake;
            NSLog(@"Taken by %@\nCurrent free:%ld, occupied: %ld", [[NSThread currentThread] name], _cake, _occupied);
        }
        [_lock unlock];
    }
}

NSOperation

NSOperation 做的事情比 NSThread 更多一些。通过继承 NSOperation,可以使子类获得一些线程相关的特性,进而可以安全地管理线程生命周期。
比如,以线程安全的方式建立状态,取消线程。配合 NSOperationQueue,可以控制线程间的优先级和依赖性。这就给出了一套线程管理的基本方法。NSOperation 代表了一个独立的计算单元。一般,我们会把计算任务封装进 NSOperation 这个对象。NSOperation 是抽象类,但同时也提供了两个可以直接使用的实体子类:NSInvocationOperation 和 NSBlockOperation。NSInvocationOperation 用于将计算任务封装进方法,NSBlockOperation 用于将计算任务封装进 block。NSOperationQueue 则用于执行计算任务,管理计算任务的优先级,处理计算任务之间的依赖性。NSOperation 被添加到 NSOperationQueue 中之后,队列会按优先级和进入顺序调度任务,NSOperation 对象会被自动执行。

NSOperation 提供以下任务优先级,以这些优先级设置变量 queuePriority 即可加快或者推迟操作的执行:
NSOperationQueuePriorityVeryHigh
NSOperationQueuePriorityHigh
NSOperationQueuePriorityNormal
NSOperationQueuePriorityLow
NSOperationQueuePriorityVeryLow

NSOperation 使用状态机模型来表示状态。通常,你可以使用 KVO(Key-Value Observing)观察任务的执行状态。这是其他多线程工具所不具备的功能。NSOperation 提供以下状态:
    isReady
    isExecuting
    isFinished
NSOperation 对象之间的依赖性可以用如下代码表示:
 [refreshUIOperation addDependency:requestDataOperation]; [operationQueue addOperation:requestDataOperation]; [operationQueue addOperation:refreshUIOperation];
除非 requestDataOperation 的状态 isFinished 返回 YES,不然 refreshUIOperation 这个操作不会开始。