zoukankan      html  css  js  c++  java
  • iOS 多线程之NSOperation

    知识点一

     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];
    

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

  • 相关阅读:
    typeof与instanceof
    TCP与UDP的区别
    const、let、var关键字
    基本通用的使用jdbc文件java代码连接数据库
    HTML知识点01
    ADO.NET基础02
    ADO.NET基础03
    数据库语法01
    数据库语法02
    Ubuntu16.4 内核降级
  • 原文地址:https://www.cnblogs.com/xiaowuqing/p/7545717.html
Copyright © 2011-2022 走看看