iOS线程浅析


一、线程概述

1、 iOS里面的线程按种类可分为同步线程和异步线程。同步线程指调用同步线程的地方必须等到同步线程运行完成才干够继续向下运行。而调用异步线程的地方则在运行完调用异步线程的语句后就能够继续向下运行。

2、线程按调用方式又能够大致分为下面几种类型:NSObject、NSThread、NSOperation和GCD。

NSObject和NSThread仅仅能管理单个的线程。功能较简单。GCD和NSOperation则能够进行队列等复杂操作。且效率较高。当中GCD方式最为有效,NSOperation是基于GCD封装的,功能相对来说更丰富。

3、异步线程中往往要创建自己的自己主动释放池来释放异步线程中创建的自己主动释放对象。

4、异步线程中有须要的话,要做自己的异常捕捉处理。由于当异步线程中产生异常时,主线程非常有可能会捕捉不到异步线程抛出的异常。


二、线程调用

1、NSObject

*        线程创建

NSObjcet对象自身实现了performSelectorInBackground、performSelectorOnMainThread和performSelector:onThread:withObject:等线程相关方法。


1.1 performSelectorInBackground是创建一个异步线程

   -(void)performSelectorInBackground:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait :

aSelector是在主线程中运行的方法,arg是传递的參数。wait指是否要等待aSelector运行完成。


1.2 performSelectorOnMainThread是返回主线程运行相关方法

    -(void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait:

aSelector是在主线程中运行的方法。arg是传递的參数,wait指是否要等待aSelector运行完成。


1.3 performSelector:onThread:withObject:是运行某个特定线程中的方法

    -(void)performSelector:(SEL)aSelector onThread:(NSThread *) withObject:(id)arg waitUntilDone:(BOOL)wait:

该方法一般用于线程间相互通信,即在一个线程中发送消息给还有一个线程

注:每个线程都有自己的RunLoop,但非主线程的RunLoop默认是关闭的,当须要进行非主线程的通信时,须要确保通信线程的RunLoop是开启的,否则发送给通信线程的消息不会被运行。


1.4 -(void)performSelector:withObject:afterDelay:是指在当前线程延迟运行某个方法

 *     线程的暂停、继续和取消

NSObject是无法暂停和取消线程的。


2、NSThread

 *     线程创建

NSThread有两种创建线程的方式: detachNewThreadSelector和initWithTarget.

2.1 detachNewThreadSelector:toTarget: withObject:

     调用这样的方法创建的线程会主动执行。不须要手动启动。

2.2 initWithTarget: selector:objcet:

     调用这样的方式新建一个线程,新建完毕后须要调用NSThread的start方法来启动线程。


 *     线程的取消

调用NSThrea的cancel方法就可以取消线程,但正在运行的线程不会立即结束。所以NSThread的cancel方法的实质意义是把线程的状态设置为已取消,然后编代码时就能够依赖线程的状态去结束掉线程。


 *     线程的暂停和继续

NSThread没有提供暂停的方法


3、NSOperation

 *      线程创建

NSOperation通常和NSOperationQueue配对使用,创建好NSOperation对象后加入到NSOperationQueue中,NSOperationQueue就可以为我们管理NSOperation。包含为NSOperation配置异步线程和启动等。


NSOperationQueue按类型分为:主队列和自己定义队列。

主队列执行在主线程上。而自己定义队列在后台执行。主队列获取方式:[NSOperationQueue mainQueue];自己定义队列获取方式:[[NSOperationQueue alloc] init]。


NSOperation按类型分为:NSOperation、NSBlockOperation和NSInvocationOperation。


3.1 NSOperation:

    NSOperation是一个虚类,我们须要继续NSOperation来创建子类,并重写main方法或start方法。重写main方法非常easy,仅仅须要重写好main方法,不须要管理一些状态属性(如isExecuted和isFinished),当main方法返回就假定操作结束了;而重写start方法则更灵活,拥有很多其它的控制权,可是状态属性信息则须要自己控制。


3.2 NSBlockOperation:

NSBlockOperation是调用blockOperationWithBlock方法以一个block作为參数创建的一个operation对象,而且在对象实例化后还能够调用addExecutionBlock方法动态加入block,但加入动作须要在operation运行前发生,通常也就是在operation加入到NSOperationQueue前。否则非常可能产生异常和莫名错误。NSBlockOperation的业务逻辑操作主要写在block中。


3.3 NSInvocationOperation:

   NSInvocationOperation是以一个SEL方法或NSInvocation为參数初始化的operation对象。NSInvocationOperation的业务逻辑操作主要放在相应的SEL方法或NSInvocation对象中。


 *     线程的暂定和继续

调用NSOperationQueue对象的setSuspended:YES就可以暂停NSOperationQueue中待运行线程的运行,然后调用setSuspended:NO就可以继续运行。


 *     线程的取消

调用NSOperation对象的cancel方法会取消单个NSOperation对象的运行,而调用NSOperationQueue对象的cancelAllOperation方法会取消NSOperation队列中全部对象的运行。


 *     线程依赖

假设NSOperation对象有运行顺利要求的话,比方operationB须要在operationA运行完成后才干够运行,那就能够通过设置NSOperation之间的依赖关系来实现:[operationB addDependency:operationA]。


 *     手动运行

假设NSOperation不和NSOperationQueue配对使用,这时就须要调用NSOperation的start方法来运行NSOperation,通常要重写isExecuting,isFinished,start和main等方法,假设要实现并发操作,则还要重写isConcurrent方法。假设NSOperation间有依赖关系,则还要重写isReady方法。

示比例如以下:


@interface HandOperation(){

        BOOL executing; // 是否正在运行

        BOOL finished;//  是否运行结束

}

-(void)completeOperation;// 结束后的状态处理方法

@end


@implementation HandOperation

#pragma mark - Lifecycle Methods

-(id)init{

     self = [super init];

     if(self){

         executing = NO;

         finished = NO;

     }

    return self;

}

-(BOOL)isConcurrent{

    return YES;

}


-(BOOL)isExecuting{

      return executing;

}


-(BOOL)isFinished{

     return finished;

}


-(BOOL)isReady{

    return [super isReady];

}


-(void)start{

     if([self isCancelled]){

         [self willChangeValueForKey:@“isFinished”];

         finished = YES;

         [self didChangeValueForKey:@“isFinished”];

         return;

     }

      [self willChangeValueForKey:@“isExecuting”];

      executing = YES;

      [NSThread detachNewThreadSelector:@selector(main) toTarget:self withObject:nil];

      [self didChangeValueForKey:@“isExecuting”];

}


-(void)main{

     @try{

           @autoraleasepool{

                [self handleForTask];

            }

            [self completeOperation];

     }

     @catch(NSException *exception){


     }

     @finally{


     }

}


#pragma mark - Custom Methods

-(void)completeOperation{

     [self willChangeValueForKey:@“isFinished”];

     [self willChangeValueForKey:@“isExecuting”];

     executing = NO;

     finished = YES;

     [self didChangeValueForKey:@“isExecuting”];

     [self didChangeValueForKey:@“isFinished”];

}


//业务处理方法

-(void)handleForTask{

     for(int i=0;i<10;i++){

         if(![self isCancelled]){

               NSLog(@“%s %i”,__func__,i);

               sleep(1);

         }

     }

}


4、GCD

 *     线程创建

GCD是Grand Central Dispatch的缩写。是Apple开发的一个多核编程的解决方式。GCD一般是把block以dispatch_async或dispatch_sync的方式加入到dispatch_queue_t队列中来创建线程: dispatch_async(dispatch_queue_t queue ,dispatch_block block)。

dispatch_async为异步加入,等dispatch_async语句运行完成后就可以继续运行下去;而dispatch_sync为同步加入,须要等dispatch_sync加入的block内容运行完成后才干够继续向下运行。

dispatch_queue_t分为三种类型: Serial Queues、Main Queues和Concurrent Queues。


4.1 Serial Queues

    Serial Queues称为串行队列,Serial Queues队列中的任务仅仅能顺序运行,一次运行一个。我们能够在Serial Queues中运行有依赖关系的任务或同步任务。

    Serial Queues队列之间是能够并发运行的。

    Serial Queues是通过dispatch_queue_create(“testQueue”,NULL)语句创建的,“testQueue”是队列标识符。NULL相应一个表示队列属性的參数,仅仅要传入NULL或DISPATCH_QUEUE_SERIAL就可以获取一个串行队列。


4.2 Main Queues

    Main Queues 称为主线程队列,全部提交至Main Queues中的任务都会在主线程中运行,所以Main Queues也是一个串行队列。

    Main Queues能够通过dispatch_get_main_queue()语句获取到,Main Queues是全局性的队列


4.3 Concurrent Queues

    Concurrent Queues称为并行队列,全部提交至Concurrent Queues中的任务都是并行运行的。Concurrent Queues又分为Global Queues和User Concurrent Queues。Global Queues由系统依据优先级提供四个不同的dispatch queue。

Global Queues能够通过dispatch_get_global_queue(dispatch_queue_priority_t priority,unsigned long flags)语句获取到。priority是优先级,优先级有DISPATCH_QUEUE_PRIORITY_HIGH、DISPATCH_QUEUE_PRIORITY_DEFAULT、DISPATCH_QUEUE_PRIORITY_LOW、DISPATCH_QUEUE_PRIORITY_BACKGROUND四种:flags是保留字段,现阶段传入0就可以。


User Concurrent Queues是通过dispatch_queue_create(“testQueue”,DISPATCH_QUEUE_CONCURRENT)语句创建的,“testQueue”是队列标识符,DISPATCH_QUEUE_CONCURRENT表示队列为并行队列。


*     线程的暂停和继续

     调用dispatch_suspend(dispatch_queue_t)就可以挂起队列。使队列中待运行的任务暂停运行,但正在运行的任务还是会继续运行。

     调用dispatch_resume(dispatch_queue_t)即能够使挂起的队列继续运行。

dispatch_suspend 和 dispatch_resume仅仅对Serial Queues 和 User Concurrent Queues有效,由于Main Queues 和Global Queues都是全局队列。


 *     线程的取消

GCD中没有显式的线程取消方法调用。仅仅能在代码中依据预先设置的标志位去实现取消操作。


 *     dispatch_group_async的使用 

dispatch_group_async能够实现监听一组任务是否完毕,完毕后得到通知运行其它操作。

使用dispatch_group_async加入一组任务后。能够使用dispatch_group_wait方法同步等待所有任务运行完成,然后才运行之后的其它任务;也能够使用dispatch_group_notify异步监听前面的任务,等前面任务运行完成后触发dispatch_group_notify中的处理事件。

例如以下:


dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);

dispatch_group_t group = dispatch_group_create();

dispatch_group_async(group,globalQueue,^{

    @autoreleasepool{

         for(int i=0;i<5;i++){

             NSLog(@“001 %i”,i);

             sleep(1);

         }   

    }

});

dispatch_group_async(group,globalQueue,^{

      

     @autoreleasepool{

           for(int i=0;i<5;i++){

             NSLog(@“002 %i”,i);

             sleep(1);

           }   

     }

});


dispatch_group_wait(group,DISPATCH_TIME_FOREVER);


/*

  dispatch_group_notify(group,globalQueue,^{

        @qutoreleasepool{

            NSLog(@“notify End”);

        }

  });

*/

dispatch_release(group);


 *     dispatch_barrier_async的使用

dispatch_barrier_async是在前面的任务运行结束后它才运行,并且它后面的任务等它运行完毕后才运行。

dispatch_barrier_async(dispatch_queue_t queue,dispatch_block_t block),queue必须是自己定义的并行队列,假设是其它队列,那么dispatch_barrier_async的效果和dispatch_sync是同样的。


 *     dispatch_apply 的使用

dispatch_apply能够运行某个代码片段N次,能够用在相互间没依赖关系的并行计算等。代码例如以下:

dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_PRIORITY_DEFAULT,0);

__block int sum = 0;

dispatch_apply(10,globalQueue,^(size_t i){

     sum += i;

});


Demo下载链接:http://download.csdn.net/download/changyou0730/7427215


原文地址:https://www.cnblogs.com/jzssuanfa/p/6767329.html