iOS多线程总结

今天没什么事做就对iOS的多线程做一次总结,纯属个人看法,初学者可以参考下。对于多线程我想无论是面试还是实际开发大家都不会陌生;

严格意义来讲iOS多线程算是4种:

  1. PThreads
  2. NSThread
  3. GCD
  4. NSOPeration/NSOperationQueue;

PThreads

这个是基于C语音定义的POSIX Threads(简称PThreads)标准线程,但是对于iOS开发者使用率很低,原因是有二:
  1. 调用的都是C函数和语法,对于习惯OC或者Swift开发的我们来说,很蛋疼;
  2. 线程的生命周期需要我们手动管理。
这个一般用在实现操作系统和PHP里(UnixLinuxMac OS X等)
- (void)Pthreads {
    pthread_t thread;
    
    //创建一个线程并执行 start是一个函数指针
    pthread_create(&thread, NULL, start, NULL);
}

void *start(void *data) {
    //这里执行线程操作
    NSLog(@"%@",[NSThread currentThread]);
    return NULL;
}
有兴趣的同学可以看看。

NSThread

这个是苹果自己开发,NSThread是轻量级多线程生命周期需要手动管理因为扩展性不高,有很多局限性只能偶尔用用 。
上代码:
- (void)NSThread {
    
    //先创建后执行
    NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(threadRun) object:nil];
    [thread start];
    
    //创建并执行
    [NSThread detachNewThreadSelector:@selector(threadRun) toTarget:self withObject:nil];
    
    //perform里唯一一个多线程方法 如果线程方法要刷新UI可以使用
    //- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)wait;
    [self performSelectorInBackground:@selector(threadRun) withObject:nil];
}

- (void)threadRun {
    
    NSLog(@"threadRun:%@",[NSThread currentThread]);
}

GCD

下面是重点,Grand Central Dispatch (GCD)是Apple开发的一个多核编程的解决方法。GCD能充分利用手机性能,让运行效率更快,也是苹果主推的多线程开发方式。
在GCD中,有两个概念很重要就是任务和队列,任务分同步执行和异步执行两种方式,队列也分串行队列和并行队列,下面我们来看它们的创建和使用:

//1.初始化/获取系统队列
    //获取主队列 ()一般只负责刷新UI,耗时任务都交给其他线程
    dispatch_queue_t queue = dispatch_get_main_queue();
    
    //创建自己的队列
    //串行队列
    dispatch_queue_t queue1 = dispatch_queue_create("队列标识符", nil);
    
    dispatch_queue_t queue2 = dispatch_queue_create("队列标识符", DISPATCH_QUEUE_SERIAL);
    
    //并行队列
    dispatch_queue_t queue3 = dispatch_queue_create("队列标识符", DISPATCH_QUEUE_CONCURRENT);
    
    //获取全局并行队列  只要是并行任务一般都加入到这个队列。这是系统提供的一个并发队列。
    dispatch_queue_t queue4 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    //2.任务的创建和执行方法(同步和异步)
    //同步任务
    dispatch_sync(queue3, ^{
        
        NSLog(@"GCD-同步%@",[NSThread currentThread]);
        sleep(5);
        NSLog(@"GCD-同步—后%@",[NSThread currentThread]);
    });
    
    //异步任务
    dispatch_async(queue3, ^{
        
        NSLog(@"GCD-异步%@",[NSThread currentThread]);
    });

从上面的代码可以看出队列还主队列(系统队列)还有自定义队列(多线程),自定义队列创建的时候两个参数第一个是标识符可以为空;第二个为空或者DISPATCH_QUEUE_SERIAL为串行队列,DISPATCH_QUEUE_CONCURRENT为并行队列。还有一个全局并行队列一般的并发任务都会加入这个队列,其实无论是并行队列还是串行队列都是以先进先出原则,区别在于并行队列是取一个开一个线程执行,在取下一个,中间取的时间很快;串行队列是取出一个执行完成以后再取出下一个,一个一个的执行。需要注意的是GCD会根据系统资源限制并行数量。
//3.队列组 队列组可以将很多队列添加到一个组里,这样做的好处是,当这个组里所有的任务都执行完了,队列组会通过一个方法通知我们。
    //3.1创建队列组
    dispatch_group_t group = dispatch_group_create();
    //3.2创建队列
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    //3.3多次使用队列组的方法执行任务,只有异步方法
    //执行3此循环
    dispatch_group_async(group, queue, ^{
        
        for (int i = 0; i < 3; i++) {
            NSLog(@"group-01:%@",[NSThread currentThread]);
        }
        
    });
    
    //主队列执行8此循环
    dispatch_group_async(group, dispatch_get_main_queue(), ^{
       
        for (int i = 0; i < 8; i++) {
            NSLog(@"group-02:%@",[NSThread currentThread]);
        }
    });
    
    //执行5次循环
    dispatch_group_async(group, queue, ^{
       
        for (int i = 0; i < 5; i++) {
            NSLog(@"group-03:%@",[NSThread currentThread]);
        }
    });
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        
        NSLog(@"完成-04:%@",[NSThread currentThread]);
    });

NSOperation/NSOperationQueue

NSOperation 是苹果公司对 GCD的封装,完全面向对象,所以使用起来更好理解。大家可以看到 NSOperation NSOperationQueue分别对应 GCD任务队列

 NSOperation只是一个抽象类,所以不能封装任务。但它有 2个子类用于封装任务。

 分别是:NSInvocationOperation NSBlockOperation

 创建一个 Operation后,需要调用 start方法来启动任务,它会默认在当前队列同步执行。

 当然你也可以在中途取消一个任务,只需要调用其 cancel方法即可


//1.创建
    //NSInvocationOperation
    NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(threadRun) object:nil];
    //开始执行
    [operation start];
    
    //NSBlockOperation
    NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{
       
        NSLog(@"blockOperation:%@",[NSThread currentThread]);
    }];
    
    /*
    NSBlockOperation 还有一个方法:addExecutionBlock: ,通过这个方法可以给 Operation 添加多个执行 Block。这样 Operation 中的任务会并发执行,它会在主线程和其它的多个线程 执行这些任务
     */
    for (int i = 0; i < 5; i++) {
        [blockOperation addExecutionBlock:^{
           
            NSLog(@"blockOperation-第%d次:%@",i,[NSThread currentThread]);
        }];
    }
    [blockOperation start];
    /*
     看过上面的内容就知道,我们可以调用一个 NSOperation 对象的 start() 方法来启动这个任务,但是这样做他们默认是 同步执行 的。就算是 addExecutionBlock 方法,也会在 当前线程和其他线程 中执行,也就是说还是会占用当前线程。这是就要用到队列 NSOperationQueue 了。而且,按类型来说的话一共有两种类型:主队列、其他队列。只要添加到队列,会自动调用任务的 start() 方法
     */
    //NSOperationQueue 获取主队列(串行)
    NSOperationQueue *queue = [NSOperationQueue mainQueue];
    
    //创建其他队列
    NSOperationQueue *queue1 = [[NSOperationQueue alloc] init];
    
    NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
        
        NSLog(@"%@",[NSThread currentThread]);
    }];
    //这里可以添加多个operation
    [queue1 addOperation:operation1];

NSOperation 有一个非常实用的功能,那就是添加依赖。比如有 3个任务:A:从服务器上下载一张图片,B:给这张图片加个水印,C:把图片返回给服务器。这时就可以用到依赖了:

//1.任务一:下载图片
    NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
        
        NSLog(@"下载图片:%@",[NSThread currentThread]);
    }];
    //2.任务二:打水印
    NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{
        
        NSLog(@"打水印:%@",[NSThread currentThread]);
    }];
    //3.任务三:上传图片
    NSBlockOperation *operation3 = [NSBlockOperation blockOperationWithBlock:^{
        
        NSLog(@"上传图片:%@",[NSThread currentThread]);
    }];
    //4.设置依赖  注意:不能添加相互依赖,会死锁,比如 A依赖B,B依赖A。
    [operation2 addDependency:operation1];  //任务二依赖任务一
    [operation3 addDependency:operation2];  //任务三依赖任务二
    
    //5.创建队列并加入
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    [queue addOperations:[NSArray arrayWithObjects:operation1,operation2,operation3, nil] waitUntilFinished:NO];
以上只是一些基本使用方法,想了解更多可以去网上找或者去看官方文档;

使用多线程我们就需要考虑数据同步的问题

其他

互斥锁:给需要同步的代码块加一个互斥锁,就可以保证每次只有一个线程访问此代码块。

@synchronized(self) {
        //需要执行的代码块
    }
我们也可以在队列的结尾加一个串行队列,来达到数据同步的效果方法有很多。
参考http://www.jianshu.com/p/0b0d9b1f1f19
Demo下载地址:http://download.csdn.net/download/pianzhidenanren/9478706

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值