博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

iOS 多线程之NSOperation

Posted on 2017-09-22 09:21  肖无情  阅读(187)  评论(0编辑  收藏  举报

知识点一

 NSOperation是个抽象类。只能使用它的子类来封装任务。有三种方式来封装任务。

  1. 使用子类NSInvocationOperation
  2. 使用子类NSBlockOperation
  3. 定义继承自NSOperation的子类,通过实现内部相应的方法来封装任务。

NSOperation(不使用NSOperationQueue的情况下)需要使用start() 才能开启操作, 并且默认情况下(只有一个操作,如果有两个或多个操作呢?)在当前线程中同步执行操作;

注意:当前线程的判定条件是是start() 调起的地方,不是operation声明 或者执行任务操作的线程中,也就是说start()在哪一线程中调起,改操作就会在那一个线程中执行,无论 具体的任务操作是在哪一个线程中定义的;举个例子: 

//main线程中声明NSBlockOperation
 op = [[NSBlockOperation alloc] init];

//在分线程中添加具体的操作 [NSThread detachNewThreadWithBlock:^{ [op addExecutionBlock:^{ int i = 0; while (i<20) { i++; [NSThread sleepForTimeInterval:1]; NSLog(@"具体操作指令:%@:::%d",[NSThread currentThread],i); } }]; }];
- (void)gotostart{
    NSLog(@"哪一个?:%@===%@",[NSThread currentThread],[NSThread currentThread].name);
    [op start];
}
- (void)buttonClick{
    //点击button 创建一个新的线程   在新线程中start();
    NSThread *thread  =  [[NSThread alloc] initWithTarget:self selector:@selector(gotostart) object:nil];
    [thread setName:@"我是新的线程"];
    [thread start];
}
2015-09-18 23:21:01.980 af[15270:6402146] 定义NSBlockOperation的线程:<NSThread: 0x600000066b00>{number = 1, name = main}
2015-09-18 23:21:01.981 af[15270:6402196] 创建操作的线程:<NSThread: 0x6000000698c0>{number = 3, name = (null)}
2015-09-18 23:21:11.892 af[15270:6402575] 调用start的线程:<NSThread: 0x60000006ebc0>{number = 4, name = 我是新的线程}===我是新的线程
2015-09-18 23:21:12.893 af[15270:6402575] 具体操作指令线程:<NSThread: 0x60000006ebc0>{number = 4, name = 我是新的线程}:::1
2015-09-18 23:21:13.898 af[15270:6402575] 具体操作指令线程:<NSThread: 0x60000006ebc0>{number = 4, name = 我是新的线程}:::2
2015-09-18 23:21:14.899 af[15270:6402575] 具体操作指令线程:<NSThread: 0x60000006ebc0>{number = 4, name = 我是新的线程}:::3
2015-09-18 23:21:15.903 af[15270:6402575] 具体操作指令线程:<NSThread: 0x60000006ebc0>{number = 4, name = 我是新的线程}:::4
2015-09-18 23:21:16.906 af[15270:6402575] 具体操作指令线程:<NSThread: 0x60000006ebc0>{number = 4, name = 我是新的线程}:::5

 如果只有一个操作(操作1)的时候会在start函数调起的线程中同步执行操作,如果有两个或多个操作呢?

答:会开启新的线程,在新的线程中执行第二个操作(操作2) 此时操作1的线程和操作2的线程是并发的;操作2线程内部是同步的

op = [[NSBlockOperation alloc] init];
    NSLog(@"定义NSBlockOperation的线程:%@",[NSThread currentThread]);
    
    [NSThread detachNewThreadWithBlock:^{
        NSLog(@"创建操作的线程:%@",[NSThread currentThread]);
        [op addExecutionBlock:^{
            int i = 0;
            while (i<10) {
                i++;
                [NSThread sleepForTimeInterval:1];
                NSLog(@"第一个操作:%@:::%d",[NSThread currentThread],i);
            }
        }];

        [op addExecutionBlock:^{
            [NSThread detachNewThreadWithBlock:^{
                int i = 0;
                while (i<20) {
                    i++;
                    [NSThread sleepForTimeInterval:1];
                    NSLog(@"具体操作指令线程A:%@:::%d",[NSThread currentThread],i);
                }
            }];
            [NSThread detachNewThreadWithBlock:^{
                int i = 0;
                while (i<20) {
                    i++;
                    [NSThread sleepForTimeInterval:1];  
                    NSLog(@"具体操作指令线程B:%@:::%d",[NSThread currentThread],i);
                } 
            }]; 
        }]; 
    }];
    

 

2015-09-18 23:44:13.163 af[15337:6437620] 第一个操作:<NSThread: 0x600000078e80>{number = 4, name = 我是新的线程}:::7
2015-09-18 23:44:13.612 af[15337:6437292] 具体操作指令线程A:<NSThread: 0x600000078cc0>{number = 5, name = (null)}:::7
2015-09-18 23:44:14.168 af[15337:6437620] 第一个操作:<NSThread: 0x600000078e80>{number = 4, name = 我是新的线程}:::8
2015-09-18 23:44:14.675 af[15337:6437292] 具体操作指令线程A:<NSThread: 0x600000078cc0>{number = 5, name = (null)}:::8
2015-09-18 23:44:15.174 af[15337:6437620] 第一个操作:<NSThread: 0x600000078e80>{number = 4, name = 我是新的线程}:::9
2015-09-18 23:44:15.741 af[15337:6437292] 具体操作指令线程A:<NSThread: 0x600000078cc0>{number = 5, name = (null)}:::9
2015-09-18 23:44:16.180 af[15337:6437620] 第一个操作:<NSThread: 0x600000078e80>{number = 4, name = 我是新的线程}:::10
2015-09-18 23:44:16.814 af[15337:6437292] 具体操作指令线程A:<NSThread: 0x600000078cc0>{number = 5, name = (null)}:::10
2015-09-18 23:44:17.884 af[15337:6437292] 具体操作指令线程A:<NSThread: 0x600000078cc0>{number = 5, name = (null)}:::11
2015-09-18 23:44:18.900 af[15337:6437292] 具体操作指令线程A:<NSThread: 0x600000078cc0>{number = 5, name = (null)}:::12
2015-09-18 23:44:19.970 af[15337:6437292] 具体操作指令线程A:<NSThread: 0x600000078cc0>{number = 5, name = (null)}:::13
2015-09-18 23:44:21.040 af[15337:6437292] 具体操作指令线程A:<NSThread: 0x600000078cc0>{number = 5, name = (null)}:::14
2015-09-18 23:44:22.081 af[15337:6437292] 具体操作指令线程A:<NSThread: 0x600000078cc0>{number = 5, name = (null)}:::15
2015-09-18 23:44:23.155 af[15337:6437292] 具体操作指令线程A:<NSThread: 0x600000078cc0>{number = 5, name = (null)}:::16
2015-09-18 23:44:24.226 af[15337:6437292] 具体操作指令线程A:<NSThread: 0x600000078cc0>{number = 5, name = (null)}:::17
2015-09-18 23:44:25.299 af[15337:6437292] 具体操作指令线程A:<NSThread: 0x600000078cc0>{number = 5, name = (null)}:::18
2015-09-18 23:44:26.374 af[15337:6437292] 具体操作指令线程A:<NSThread: 0x600000078cc0>{number = 5, name = (null)}:::19
2015-09-18 23:44:27.387 af[15337:6437292] 具体操作指令线程A:<NSThread: 0x600000078cc0>{number = 5, name = (null)}:::20
2015-09-18 23:44:28.389 af[15337:6438077] 具体操作指令线程B:<NSThread: 0x608000067f40>{number = 6, name = (null)}:::1
2015-09-18 23:44:29.389 af[15337:6438077] 具体操作指令线程B:<NSThread: 0x608000067f40>{number = 6, name = (null)}:::2
2015-09-18 23:44:30.395 af[15337:6438077] 具体操作指令线程B:<NSThread: 0x608000067f40>{number = 6, name = (null)}:::3

 那么 默认情况下 系统线程池会开启多少个线程 ?

答:默认66个线程 其中有2个是系统的,64个是我们可以使用的;

最大并发数不要乱写(5以内),不要开太多,一般以2~3为宜,因为虽然任务是在子线程进行处理的,但是cpu处理这些过多的子线程可能会影响UI,让UI变卡。 

线程的花销:(来自官方文档,没有研究这个花销是否包含上下文切换时的场景记忆等花销);

512 KB (secondary threads)

8 MB (OS X main thread)

1 MB (iOS main thread)

知识点二: 

NSOperationQueue 

    [NSOperationQueue mainQueue]; 

   queue = [[NSOperationQueue alloc] init];

operation加入到队列中,如果当前operation个数(线程(线程个数并不一定等于operation个数))小于可以开启的最大peration(线程)个数,那么它会在很短的时间内就开始了这一个operation;

添加的operation 都是在分线程中执行的;

 

   queue.maxConcurrentOperationCount = 2;
    // 这个参数表示的是operation的最大个数,并不是开启线程的最大个数

    //一个operation可以有多个操作,第一个操作在当前线程,其他操作开启了新的线程;每一个线程都是同步执行的;

 

    op = [[NSBlockOperation alloc] init];
    [op addExecutionBlock:^{
        int i = 0;
        while (i<10) {
            i++;
            [NSThread sleepForTimeInterval:1];
            NSLog(@"op_1------:%@:::%d",[NSThread currentThread],i);     
        } 
    }];
    
    [op addExecutionBlock:^{
        int i = 0;
        while (i<20) {
            i++;
            [NSThread sleepForTimeInterval:1];
            NSLog(@"op_2=-----%@:::%d",[NSThread currentThread],i);
        }
    }];
    
    //    blocks cannot be added after the operation has started executing or finished'

    op1 = [[NSBlockOperation alloc] init];
    
    [op1 addExecutionBlock:^{
        [NSThread sleepForTimeInterval:2];
        int i = 0;
        while (i<20) {
            i++;
            [NSThread sleepForTimeInterval:1];            
            NSLog(@"op1=-----%@:::%d",[NSThread currentThread],i);
        }
    }];
    
    op2 = [[NSBlockOperation alloc] init];
    [op2 addExecutionBlock:^{
        int i = 0;
        while (i<20) {
            i++;
            [NSThread sleepForTimeInterval:1];
            NSLog(@"op2=-----%@:::%d",[NSThread currentThread],i);
        }
    }];

 添加依赖等设置;

//op1 依赖于op2 也就是说op2执行完之后 op1才开始 (网络请求也是这个顺序,执行顺序,并不是数据返回顺序)
      [op1 addDependency:op2];
    
      [queue addOperation:op];


这一个是阻塞当前线程; 直到op这个操作执行完成;可用于线程执行顺序的同步

               [op waitUntilFinished];


[queue addOperation:op1]; [queue addOperation:op2];

[op1 cancel];
[queue cancelAllOperations];

 

操作的是在队列中等待的操作;