iOS 多线程常规使用 NSThread、GCD、NSOperation

NSThread三种创建方式:需要手动管理线程

• init创建 ,start启动

• detachNewThreadSelector创建好之后自动启动

• performSelectorInBackground创建好之后直接启动

init创建
/**
     init 方式创建 
    1. 默认开启新线程
    2. 需要 start 启动
*/
 NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(threadMethodOne:) object:nil];

 [thread start];
/**
     init  block方式 
    1. 默认开启新线程
*/
    NSThread *thread1 = [[NSThread alloc] initWithBlock:^{

        NSLog(@"block线程执行了%@",[NSThread currentThread]);
    }];

NSThread 类方法 detachNewThreadSelector
/**
    类方法创建 
    1. 默认开启新线程
    2. 创建及启动
*/
    [NSThread detachNewThreadSelector:@selector(threadMethodOne:) toTarget:self withObject:nil];
NSThread 隐式创建 performSelectorInBackground
/**
    隐式创建 
    1. 默认开启新线程
    2. 创建后自动启动
*/
  [self performSelectorInBackground:@selector(threadMethodOne:) withObject:nil];

  //主线程
   [self performSelectorOnMainThread:@selector(threadMethodOne:) withObject:nil waitUntilDone:nil];
NSThread 相关类方法
//返回当前线程
[NSThread currentThread];
//阻塞休眠
[NSThread sleepForTimeInterval:2];
//退出线程
[NSThread exit];
//判断当前线程是否为主线程
[NSThread isMainThread];
//判断当前线程是否是多线程
[NSThread isMultiThreaded];
//主线程的对象
NSThread *mainThread = [NSThread mainThread];
NSThread 属性
NSThread *thread = [[NSThread alloc] init];
//线程是否在执行
thread.isExecuting;
//线程是否被取消
thread.isCancelled;
//线程是否完成
thread.isFinished;
//是否是主线程
thread.isMainThread;
//线程的优先级,取值范围0.0到1.0,默认优先级0.5,1.0表示最高优先级,优先级高,CPU调度的频率高
 thread.threadPriority;

GCD 的使用

• GCD会自动利用更多的CPU内核

• GCD自动管理线程的生命周期(创建线程,调度任务,销毁线程等)

• 程序员只需要告诉 GCD 想要如何执行什么任务,不需要编写任何线程管理代码

• sync : 同步,不开启新线程
• async : 异步 , 开启新线程

• 队列: 装载线程任务的队形结构。(系统以先进先出的方式调度队列中的任务执行)。在GCD中有两种队列:串行队列和并发队列。

• 并发队列:线程可以同时一起进行执行。实际上是CPU在多条线程之间快速的切换。(并发功能只有在异步(dispatch_async)函数下才有效)

• 串行队列:线程只能依次有序的执行。

• GCD总结:将任务(要在线程中执行的操作block)添加到队列(自己创建或使用全局并发队列),并且指定执行任务的方式(异步dispatch_async,同步dispatch_sync)

串行同步

  - (void)GCD_serial_sync{
    //1 。 串行同步  顺序执行  不开启新线程
    dispatch_queue_t queue = dispatch_queue_create("serial_sync", DISPATCH_QUEUE_SERIAL);
    
    dispatch_sync(queue, ^{
        NSLog(@"任务1 %@" , [NSThread currentThread]);
    });
    
    dispatch_sync(queue, ^{
        NSLog(@"任务2 %@" , [NSThread currentThread]);
    });
    
    dispatch_sync(queue, ^{
        NSLog(@"任务3 %@" , [NSThread currentThread]);
    });
}
//输出结果 :任务1 、任务2、任务3  

串行异步

  - (void)GCD_serial_async{
    //1 。 串行异步  顺序执行  开启新线程
    dispatch_queue_t queue = dispatch_queue_create("serial_sync", DISPATCH_QUEUE_SERIAL);
    
    dispatch_async(queue, ^{
        NSLog(@"任务1 %@" , [NSThread currentThread]);
        
    });
    
    dispatch_async(queue, ^{
        NSLog(@"任务2 %@" , [NSThread currentThread]);
    });
    
    dispatch_async(queue, ^{
        NSLog(@"任务3 %@" , [NSThread currentThread]);
    });
 }
//输出结果 :任务1 、任务2、任务3  

并发 同步

- (void)GCD_concurrent_sync{
    //1 。 并发同步  顺序执行  不开启新线程
    dispatch_queue_t queue = dispatch_queue_create("serial_sync", DISPATCH_QUEUE_CONCURRENT);
    
    dispatch_sync(queue, ^{
        NSLog(@"任务1 %@" , [NSThread currentThread]);
        
    });
    
    dispatch_sync(queue, ^{
        NSLog(@"任务2 %@" , [NSThread currentThread]);
    });
    
    dispatch_sync(queue, ^{
        NSLog(@"任务3 %@" , [NSThread currentThread]);
    });
}
//输出结果 :任务1 、任务2、任务3  

并发 异步

- (void)GCD_concurrent_async{
    //1 。 并发异步 同时执行    开启新线程
    dispatch_queue_t queue = dispatch_queue_create("serial_sync", DISPATCH_QUEUE_CONCURRENT);
    
    dispatch_async(queue, ^{
        NSLog(@"任务1 %@" , [NSThread currentThread]);
        
    });
    
    dispatch_async(queue, ^{
        NSLog(@"任务2 %@" , [NSThread currentThread]);
    });
    
    dispatch_async(queue, ^{
        NSLog(@"任务3 %@" , [NSThread currentThread]);
    });

}
//输出结果 :顺序不定 

主队列

- (void)GCD_main_async{
    // 异步可以执行 
    dispatch_queue_t queue = dispatch_get_main_queue();
    NSLog(@"任务1");
    
    dispatch_async(queue, ^{
        NSLog(@"任务2 %@" , [NSThread currentThread]);
        
    });
    
    dispatch_async(queue, ^{
        NSLog(@"任务3 %@" , [NSThread currentThread]);
    });
//输出结果 : 任务1、任务2、任务3

//    dispatch_sync(queue, ^{
//        NSLog(@"任务3 %@" , [NSThread currentThread]);
//    });
/**
  如果添加上面你的同步代码,将会形成死锁
  输出结果: 任务1
*/
}

线程间的通信

- (void)GCD_communication{
    //将耗时操作放到子线程
    //刷新ui放到主线程
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        NSLog(@"在子线程中睡觉2s");
        [NSThread sleepForTimeInterval:2];
        
        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"回到主线程干事情");
            
        });
        
    });

}

GCD栅栏

- (void)GCD_barrier{
    //1. 同步栅栏会阻塞线程 同步是阻塞当前线程
    //2. 异步栅栏不会阻塞线程,阻塞的是队列列
    dispatch_queue_t queue = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(queue, ^{
        NSLog(@"任务1");
        
    });
    
    dispatch_async(queue, ^{
        NSLog(@"任务2");
        
    });
    
    dispatch_barrier_sync(queue, ^{
        NSLog(@"栅栏");
    });
    dispatch_async(queue, ^{
        NSLog(@"任务3");
        
    });
    
    dispatch_async(queue, ^{
        NSLog(@"任务4");
        
    });
    NSLog(@"任务5");
/**
  栅栏同步 dispatch_barrier_sync : 任务1和任务2在栅栏前面,任务5在任务3和任务4 前面,中间是栅栏
  任务1、任务2、栅栏、任务5、任务3、任务4

  栅栏异步 dispatch_barrier_async :任务1、任务2在栅栏前面、任务3、任务4在栅栏后面,任务      5随时可能执行完成
  任务1、任务5、任务2、栅栏、任务3、任务4

*/
}

GCD Group

-(void)GCD_group{
    dispatch_group_t group = dispatch_group_create();
    
    dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
        [NSThread sleepForTimeInterval:2];
        NSLog(@"耗时任务1 %@",[NSThread currentThread]);
        
    
    });
    
    dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
        [NSThread sleepForTimeInterval:2];
        NSLog(@"耗时任务2 %@",[NSThread currentThread]);
    });
    
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        NSLog(@"任务3");
    });
}
//输出结果: 耗时任务1和耗时任务2没有顺序、任务3

GCD 延迟after 快速迭代appy

- (void)GCD_after_apply{
    //延迟执行
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2*NSEC_PER_SEC)), dispatch_get_global_queue(0, 0), ^{
        NSLog(@"延迟执行2s");
        dispatch_apply(3, dispatch_get_global_queue(0, 0), ^(size_t index) {
          //输出结果 : 0 1 2
            NSLog(@"%zu",index);
        });
    });
}

GCD 计时器

//gcd 计时器
- (void)GCD_time{
    
    dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(0, 0) );
    dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC, 1 * NSEC_PER_SEC);
    dispatch_source_set_event_handler(timer, ^{
        NSLog(@"定时器");
      
    });
    dispatch_resume(timer);
    
}

NSOperation 使用

  1. 创建任务:先将需要执行的操作封装到NSOperation对象中。
  2. 创建队列:创建NSOperationQueue。
  3. 将任务加入到队列中:将NSOperation对象添加到NSOperationQueue中。
  4. 调用start开启,谁先开启,谁先执行

创建方式

• initWithTarget 在主线程执行 没有开启新的队列
• blockOperationWithBlock 只有一个任务在主线程执行 。多个任务并发,任务1在主线程,其他在子线程,开启新线程

- (void)NSOperation_default{
    //在主线程执行 没有开启新的队列
    NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(invocationOperation) object:nil];

    //只有一个任务在主线程执行  。多个任务并发,任务1在主线程,其他在子线程,开启新线程
    NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"block operation 任务1 %@",[NSThread currentThread]);
        
        
    }];
    [blockOperation addExecutionBlock:^{
        NSLog(@"block operation 任务2 %@",[NSThread currentThread]);

    }];
    [blockOperation addExecutionBlock:^{
        NSLog(@"block operation 任务3 %@",[NSThread currentThread]);

    }];
    
    [blockOperation start];
    [operation start];
}
//输出结果:任务1、任务2和任务3顺序随意

NSOperationQueue

• NSOperation是需要配合队列NSOperationQueue来实现多线程的。

• 非主队列(其他队列)可以实现串行或并行。

• 队列NSOperationQueue有一个参数叫做最大并发数:maxConcurrentOperationCount。

• maxConcurrentOperationCount默认为-1,直接并发执行,所以加入到‘非队列’中的任务默认就是并发,开启多线程。

• 当maxConcurrentOperationCount为1时,则表示不开线程,也就是串行。

• 当maxConcurrentOperationCount大于1时,进行并发执行。

• 系统对最大并发数有一个限制,所以即使程序员把maxConcurrentOperationCount设置的很大,系统也会自动调整。所以把最大并发数设置的很大是没有意义的。

- (void)NSOperationQueue_concurrent{
    NSOperationQueue *queue = [[NSOperationQueue alloc]init];
#任务1
    queue.maxConcurrentOperationCount = 5; //count = 1 串行 count>1并发 数字为几做多执行几个
#任务2
    NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"block 任务 %@",[NSThread currentThread]);
    }];
    NSInvocationOperation *inOPeration = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(invocationOperation) object:nil];
    [queue addOperation:blockOperation];
    [queue addOperation:inOPeration];
    
    [blockOperation addDependency:inOPeration];//任务2 依赖于任务1执行
#任务3
    [queue addOperationWithBlock:^{
            NSLog(@"使用block添加任务 %@",[NSThread currentThread]);
        
    }];
#任务4
    [queue addBarrierBlock:^{
            NSLog(@"barrier"); //使用栅栏,语gcd效果一样
    }];
#任务5
    [queue addOperationWithBlock:^{
            NSLog(@"使用block添加任务%@",[NSThread currentThread]);
        
    }];
#任务6
    [queue addOperationWithBlock:^{
            NSLog(@"使用block添加任务 %@",[NSThread currentThread]);
        
    }];
}
//输出结果: 任务1在任务2之前执行 ,任务4是栅栏,所以要在任务1,任务2,任务3之后,任务5,任务6在任务4之后,关键顺序对了就可以,其他顺序随意
//任务3 -- 任务1 -- 任务2 -- 任务4 -- 任务5 --任务6
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容