多线程-NSOperation,NSOperationQueue

NSOperation,NSOperationQueue

demo。最快熟悉的方式就是自己码一遍。

NSOperation

NSOperation是一个抽象类,我们可以直接使用其子类NSInvocationOperationNSBlockOperation,或者封装NSOperation子类来添加要在线程中执行的操作。默认情况下NSOperation单独使用时执行同步操作。

NSInvocationOperation

操作在当前线程中执行,不开启新线程。

  NSInvocationOperation *op1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(p_task1) object:nil];
  [op1 start];

NSBlockOperation

  NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"--->blockOp1-Thread:%@",[NSThread currentThread]);
    }];
    [op start];

添加操作:通过- (void)addExecutionBlock:(void (^)(void))block;NSBlockOperation添加额外的操作。这些操作可以在不同的线程中并发执行,线程的切换由系统决定。如果添加的操作较多,blockOperationWithBlock:中的操作可能会在其他线程中执行。

自定义NSOperation子类

通过重写mainstart方法来定义自己的NSOperation对象。

// 当前线程执行

@implementation CustomOperation

- (void)main {
    if (!self.cancelled) {
        NSLog(@"--->customMainOp-Thread:%@",[NSThread currentThread]);
    }
}

@end

并发执行

需要重写的方法: 必须:

可选:

@implementation ConcurrentOperation

@synthesize executing = _executing;
@synthesize finished = _finished;

- (BOOL)isExecuting {
    return _executing;
}

- (BOOL)isFinished {
    return _finished;
}

- (BOOL)isAsynchronous {
    return YES;
}

- (void)start {
    if (self.cancelled) {
        [self willChangeValueForKey:@"isFinished"];
        _finished = YES;
        [self willChangeValueForKey:@"isFinished"];
        return;
    }
    [self willChangeValueForKey:@"isExecuting"];
    [NSThread detachNewThreadSelector:@selector(main) toTarget:self withObject:nil];
    _executing = YES;
    [self willChangeValueForKey:@"isExecuting"];
}

- (void)main {
    NSLog(@"--->concurrentOp-Thread:%@",[NSThread currentThread]);
    [self willChangeValueForKey:@"isExecuting"];
    _executing = NO;
    [self didChangeValueForKey:@"isExecuting"];
    
    [self willChangeValueForKey:@"isFinished"];
    _finished  = YES;
    [self didChangeValueForKey:@"isFinished"];
}
@end

NSOperationQueue

队列类型:

操作加入到队列

addOperation

    NSOperationQueue *customQueue = [[NSOperationQueue alloc] init];
    NSInvocationOperation *op1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(p_task1) object:nil];
    
    NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
        sleep(2);
        NSLog(@"--->OpQueue1-Thread:%@",[NSThread currentThread]);
    }];
    [customQueue addOperation:op1];
    [customQueue addOperation:op3];

addOperationWithBlock

    NSOperationQueue *customQueue = [[NSOperationQueue alloc] init];
    [customQueue addOperationWithBlock:^{
        NSLog(@"--->BlockOpQueue1-Thread:%@",[NSThread currentThread]);
    }];

并发控制

operationQueue的并发控制由maxConcurrentOperationCount来控制。

NSOperation操作依赖

NSOperation依赖关系由自身管理,与Queue无关。 添加是在Operation操作执行之前添加。 防止循环依赖

NSOperation优先级 - 针对已加入到到队列中的操作有效。

typedef NS_ENUM(NSInteger, NSOperationQueuePriority) {
	NSOperationQueuePriorityVeryLow = -8L,
	NSOperationQueuePriorityLow = -4L,
	NSOperationQueuePriorityNormal = 0,
	NSOperationQueuePriorityHigh = 4,
	NSOperationQueuePriorityVeryHigh = 8
};

线程间通信

  NSOperationQueue *opQ = [[NSOperationQueue alloc] init];
    [opQ addOperationWithBlock:^{
        sleep(1);
        NSLog(@"--->1-Thread:%@",[NSThread currentThread]);
        [[NSOperationQueue mainQueue] addOperationWithBlock:^{
            NSLog(@"--->2-Thread:%@",[NSThread currentThread]);
        }];
    }];

线程安全

若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行写操作(更改变量),一般都需要考虑线程同步,否则的话就可能影响线程安全。

线程安全解决:加锁

性能对比: lock_benchmark.png

参考

https://bujige.net/blog/iOS-Complete-learning-NSOperation.html http://blog.leichunfeng.com/blog/2015/07/29/ios-concurrency-programming-operation-queues/ https://blog.ibireme.com/2016/01/16/spinlock_is_unsafe_in_ios/