iOS开发 多线程(三)转自MJ的NSOperationQueue使用

1、简介java

一个NSOperation对象能够经过调用start方法来执行任务,默认是同步执行的。也能够将NSOperation添加到一个NSOperationQueue(操做队列)中去执行,并且是异步执行的。并发

建立一个操做队列:异步

[java] view plaincopy性能

  1. NSOperationQueue *queue = [[NSOperationQueue alloc] init];  spa


2、添加NSOperationNSOperationQueue.net

1.添加一个operation线程

[java] view plaincopy设计

  1. [queue addOperation:operation];  3d


2.添加一组operationorm

[java] view plaincopy

  1. [queue addOperations:operations waitUntilFinished:NO];  


3.添加一个block形式的operation

[java] view plaincopy

  1. [queue addOperationWithBlock:^() {  

  2.     NSLog(@"执行一个新的操做,线程:%@", [NSThread currentThread]);  

  3. }];  


NSOperation添加到queue以后,一般短期内就会获得运行。可是若是存在依赖,或者整个queue被暂停等缘由,也可能须要等待。

注意:NSOperation添加到queue以后,绝对不要再修改NSOperation对象的状态。由于NSOperation对象可能会在任什么时候候运行,所以改变NSOperation对象的依赖或数据会产生不利的影响。你只能查看NSOperation对象的状态, 好比是否正在运行、等待运行、已经完成等


3、添加NSOperation的依赖对象
1.当某个NSOperation对象依赖于其它NSOperation对象的完成时,就能够经过addDependency方法添加一个或者多个依赖的对象,只有全部依赖的对象都已经完成操做,当前NSOperation对象才会开始执行操做。另外,经过removeDependency方法来删除依赖对象。

[java] view plaincopy

  1. [operation2 addDependency:operation1];  

依赖关系不局限于相同queue中的NSOperation对象,NSOperation对象会管理本身的依赖, 所以彻底能够在不一样的queue之间的NSOperation对象建立依赖关系


惟一的限制是不能建立环形依赖,好比A依赖B,B依赖A,这是错误的


2.依赖关系会影响到NSOperation对象在queue中的执行顺序,看下面的例子:

1> 没有设置依赖关系

[java] view plaincopy

  1. NSOperationQueue *queue = [[NSOperationQueue alloc] init];  

  2.   

  3. NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^(){  

  4.     NSLog(@"执行第1次操做,线程:%@", [NSThread currentThread]);  

  5. }];  

  6.   

  7. NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^(){  

  8.     NSLog(@"执行第2次操做,线程:%@", [NSThread currentThread]);  

  9. }];  

  10.   

  11. [queue addOperation:operation1];  

  12. [queue addOperation:operation2];  

打印信息:

[java] view plaincopy

  1. 2013-02-03 00:21:35.024 thread[5616:3d13] 执行第1次操做,线程:<NSThread: 0x7658570>{name = (null), num = 3}  

  2. 2013-02-03 00:21:35.063 thread[5616:1303] 执行第2次操做,线程:<NSThread: 0x765a2e0>{name = (null), num = 4}  

能够看出,默认是按照添加顺序执行的,先执行operation1,再执行operation2

2> 设置了依赖关系

[java] view plaincopy

  1. NSOperationQueue *queue = [[NSOperationQueue alloc] init];  

  2.   

  3. NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^(){  

  4.     NSLog(@"执行第1次操做,线程:%@", [NSThread currentThread]);  

  5. }];  

  6.   

  7. NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^(){  

  8.     NSLog(@"执行第2次操做,线程:%@", [NSThread currentThread]);  

  9. }];  

  10. // operation1依赖于operation2  

  11. [operation1 addDependency:operation2];  

  12.   

  13. [queue addOperation:operation1];  

  14. [queue addOperation:operation2];  

打印信息:

[java] view plaincopy

  1. 2013-02-03 00:24:16.260 thread[5656:1b03] 执行第2次操做,线程:<NSThread: 0x7634490>{name = (null), num = 3}  

  2. 2013-02-03 00:24:16.285 thread[5656:1303] 执行第1次操做,线程:<NSThread: 0x9138b50>{name = (null), num = 4}  

能够看出,先执行operation2,再执行operation1

4、修改Operations的执行顺序

对于添加到queue中的operations,它们的执行顺序取决于2点:

1.首先看看NSOperation是否已经准备好:是否准备好由对象的依赖关系肯定

2.而后再根据全部NSOperation的相对优先级来肯定。优先级等级则是operation对象自己的一个属性。默认全部operation都拥有“普通”优先级,不过能够经过setQueuePriority:方法来提高或下降operation对象的优先级。优先级只能应用于相同queue中的operations。若是应用有多个operation queue,每一个queue的优先级等级是互相独立的。所以不一样queue中的低优先级操做仍然可能比高优先级操做更早执行。

注意:优先级不能替代依赖关系,优先级只是对已经准备好的 operations肯定执行顺序。先知足依赖关系,而后再根据优先级从全部准备好的操做中选择优先级最高的那个执行。


5、设置队列的最大并发操做数量

队列的最大并发操做数量,意思是队列中最多同时运行几条线程

虽然NSOperationQueue类设计用于并发执行Operations,你也能够强制单个queue一次只能执行一个Operation。setMaxConcurrentOperationCount:方法能够配置queue的最大并发操做数量。设为1就表示queue每次只能执行一个操做。不过operation执行的顺序仍然依赖于其它因素,好比operation是否准备好和operation的优先级等。所以串行化的operation queue并不等同于GCD中的串行dispatch queue

[java] view plaincopy

  1. // 每次只能执行一个操做  

  2. queue.maxConcurrentOperationCount = 1;  

  3. // 或者这样写  

  4. [queue setMaxConcurrentOperationCount:1];  


6、取消Operations

一旦添加到operation queue,queue就拥有了这个Operation对象而且不能被删除,惟一能作的事情是取消。你能够调用Operation对象的cancel方法取消单个操做,也能够调用operation queue的cancelAllOperations方法取消当前queue中的全部操做。

[java] view plaincopy

  1. // 取消单个操做  

  2. [operation cancel];  

  3.   

  4. // 取消queue中全部的操做  

  5. [queue cancelAllOperations];  


7、等待Options完成

为了最佳的性能,你应该设计你的应用尽量地异步操做,让应用在Operation正在执行时能够去处理其它事情。若是须要在当前线程中处理operation完成后的结果,可使用NSOperation的waitUntilFinished方法阻塞当前线程,等待operation完成。一般咱们应该避免编写这样的代码,阻塞当前线程多是一种简便的解决方案,可是它引入了更多的串行代码,限制了整个应用的并发性,同时也下降了用户体验。绝对不要在应用主线程中等待一个Operation,只能在第二或次要线程中等待。阻塞主线程将致使应用没法响应用户事件,应用也将表现为无响应。

[java] view plaincopy

  1. // 会阻塞当前线程,等到某个operation执行完毕  

  2. [operation waitUntilFinished];  


除了等待单个Operation完成,你也能够同时等待一个queue中的全部操做,使用NSOperationQueue的waitUntilAllOperationsAreFinished方法。注意:在等待一个 queue时,应用的其它线程仍然能够往queue中添加Operation,所以可能会加长线程的等待时间。

[java] view plaincopy

  1. // 阻塞当前线程,等待queue的全部操做执行完毕  

  2. [queue waitUntilAllOperationsAreFinished];  


8、暂停和继续queue

若是你想临时暂停Operations的执行,可使用queue的setSuspended:方法暂停queue。不过暂停一个queue不会致使正在执行的operation在任务中途暂停,只是简单地阻止调度新Operation执行。你能够在响应用户请求时,暂停一个queue来暂停等待中的任务。稍后根据用户的请求,能够再次调用setSuspended:方法继续queue中operation的执行

[java] view plaincopy

  1. // 暂停queue  

  2. [queue setSuspended:YES];  

  3.   

  4. // 继续queue  

  5. [queue setSuspended:NO];  

相关文章
相关标签/搜索