iOS多线程总结

来源:互联网 发布:保险公司首席数据官 编辑:程序博客网 时间:2024/05/16 09:01

今天没什么事做就对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/0b0d9b1f1f19Demo下载地址:http://download.csdn.net/download/pianzhidenanren/9478706

0 0
原创粉丝点击