美文网首页
iOS 多线程---NSOperation

iOS 多线程---NSOperation

作者: iOS程序媛ing | 来源:发表于2020-09-08 08:22 被阅读0次

    NSOperation、NSOperationQueue是对GCD的进一步封装,比GCD简单易用、更易读;

    为什么使用NSOperation
    1、NSOperation可以设置任务之间的依赖关系;
    2、NSOperation可以设置任务的优先级;
    3、NSOperaion可以获取任务当前的状态isFinished(已完成)、isCancelled(已取消)、isExecuteing(正在执行)

    1、NSOperaion、NSOperationQueue操作和操作队列

    1.1 NSOperation操作

    通过NSOperation的子类NSBlockOperation和NSInvotionOperaion或者自定义创建操作
    需要注意的是,如果操作没有添加到操作队列中,需要调用start方法执行任务,如果添加到队列中,不需要调用start方法

     NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
            
        }];
        [operation start];
     NSInvocationOperation *operation2 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(invocation) object:nil];
        [operation2 start];
    
    2、NSOperationQueue

    NSOperationQueue通过设置最大并发数,来确定是串行队列还是并发队列
    (1)默认情况下最大并发数是-1,不限制开辟线程数;
    (2)当最大并发数为1时,为串行队列;
    (3)当最大并发数大于1时,为并发队列;
    maxConcurrentOperationCount = 0,不执行。默认是maxConcurrentOperationCount = -1,异步队列

    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    queue.maxConcurrentOperationCount = 0;
    

    2.1将操作添加到操作队列中
    将操作添加到操作队列中有两种方式
    第一种addOperation,创建操作后,将操作添加到队列

    [queue addOperation:operation];
    

    第二种addOperationWithBlock,直接添加任务,不需要创建操作

    [queue addOperationWithBlock:^{
            NSLog(@"执行操作");
        }];
    
    3、创建依赖

    下面表示operation依赖operation2操作,operation2操作完成后operation操作才会执行
    需要注意的是,先添加依赖关系,再将操作添加到操作队列中,否则依赖关系不起作用

     NSOperationQueue *queue = [[NSOperationQueue alloc] init];
        NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
            
        }];
      
        NSInvocationOperation *operation2 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(invocation) object:nil];
        
     [operation addDependency:operation2];
        [queue addOperation:operation];
        [queue addOperation:operation2];
       
    
    4、优先级

    NSOperaion可以通过设置优先级,改变操作执行顺序,默认情况下,操作的优先级是NSOperationQueuePriorityNormal, 我们可以通过setQueuePriority方法设置操作的优先级

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

    如果一个操作队列中既设置了优先级,也设置了依赖关系,有限执行已经准备就绪的操作,如果当前有op1、op2、op3、op4四个操作添加到队列中,op2依赖于op1,op3依赖于op2,op1和op4都没有依赖,那么op1和op4处于准备就绪状态,op2和op3处于未准备就绪状态,如果op4的优先级高于op1,当最大并发数为1的情况下那么执行顺序是op4、op1、op2、op3;如果op2或者op3的优先级高于op4,执行顺序还是如此。如果最大并发数不为1,那么执行顺序为op4、op1、op2、op3或op1、op4、op2、op3.

    5、线程间的通信
     NSOperationQueue *queue = [[NSOperationQueue alloc] init];
     NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
         NSLog(@"1===%@", [NSThread currentThread]);
         [[NSOperationQueue mainQueue] addOperationWithBlock:^{
                NSLog(@"回到主线程刷新界面");
            }];
        }];
     [queue addOperation:operation1];
    
    6、线程安全

    6.1NSOperation、NSOperationQueue 非线程安全
    下面,我们模拟火车票售卖的方式,实现 NSOperation 线程安全和解决线程同步问题。
    场景:总共有100张火车票,有两个售卖火车票的窗口,一个是广东火车票售卖窗口,另一个是广西火车票售卖窗口。两个窗口同时售卖火车票,卖完为止。

    /**
     * 非线程安全:不使用 NSLock
     * 初始化火车票数量、卖票窗口(非线程安全)、并开始卖票
     */
    - (void)initTicketStatusNotSave {
        NSLog(@"currentThread---%@",[NSThread currentThread]); // 打印当前线程
    
        self.ticketSurplusCount = 50;
    
        // 1.创建 queue1,queue1 代表广东火车票售卖窗口
        NSOperationQueue *queue1 = [[NSOperationQueue alloc] init];
        queue1.maxConcurrentOperationCount = 1;
    
        // 2.创建 queue2,queue2 代表广西火车票售卖窗口
        NSOperationQueue *queue2 = [[NSOperationQueue alloc] init];
        queue2.maxConcurrentOperationCount = 1;
    
        // 3.创建卖票操作 op1
        NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
            [self saleTicketNotSafe];
        }];
    
        // 4.创建卖票操作 op2
        NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
            [self saleTicketNotSafe];
        }];
    
        // 5.添加操作,开始卖票
        [queue1 addOperation:op1];
        [queue2 addOperation:op2];
    }
    
    /**
     * 售卖火车票(非线程安全)
     */
    - (void)saleTicketNotSafe {
        while (1) {
    
            if (self.ticketSurplusCount > 0) {
                //如果还有票,继续售卖
                self.ticketSurplusCount--;
                NSLog(@"%@", [NSString stringWithFormat:@"剩余票数:%d 窗口:%@", self.ticketSurplusCount, [NSThread currentThread]]);
                [NSThread sleepForTimeInterval:0.2];
            } else {
                NSLog(@"所有火车票均已售完");
                break;
            }
        }
    }
    

    6.2线程安全,加线程锁(使读写操作在同一线程操作,才能保证线程安全。atomic只是保证读写安全)

    - (void)saleTicketNotSafe {
        while (1) {
         [self.lock lock];
            if (self.ticketSurplusCount > 0) {
                //如果还有票,继续售卖
                self.ticketSurplusCount--;
                NSLog(@"%@", [NSString stringWithFormat:@"剩余票数:%d 窗口:%@", self.ticketSurplusCount, [NSThread currentThread]]);
                [NSThread sleepForTimeInterval:0.2];
            } else {
                NSLog(@"所有火车票均已售完");
                break;
            }
          [self.lock unlock];
        }
    }
    

    相关文章

      网友评论

          本文标题:iOS 多线程---NSOperation

          本文链接:https://www.haomeiwen.com/subject/mdrlektx.html