iOS_多线程

NSThread

NSThread是轻量级的多线程开发,使用起来也并不复杂,但是使用NSThread需要自己管理线程生命周期。

NSthread的初始化

  • 动态方法
- (id)initWithTarget:(id)target selector:(SEL)selector object:(id)argument;  

// 初始化线程  
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];  
// 设置线程的优先级(0.0 - 1.0,1.0最高级)  
thread.threadPriority = 1;  
// 开启线程  
[thread start];  

参数解析:
selector :线程执行的方法,这个selector最多只能接收一个参数target :selector消息发送的对象argument : 传给selector的唯一参数,也可以是nil

  • 静态方法
+ (void)detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)argument;  

[NSThread detachNewThreadSelector:@selector(run) toTarget:self withObject:nil];  
// 调用完毕后,会马上创建并开启新线程  
  • 隐式创建线程的方法
[self performSelectorInBackground:@selector(run) withObject:nil];  

获取当前线程

NSThread *current = [NSThread currentThread];  

获取主线程

NSThread *main = [NSThread mainThread];  

暂停当前线程

// 暂停2s  
[NSThread sleepForTimeInterval:2];  

// 或者  
NSDate *date = [NSDate dateWithTimeInterval:2 since Date:[NSDate date]];  
[NSThread sleepUntilDate:date];  

线程间的通信

  • 在指定线程上执行操作
  [self performSelector:@selector(run) onThread:thread withObject:nil waitUntilDone:YES];  
  • 在主线程上执行操作
[self performSelectorOnMainThread:@selector(run) withObject:nil waitUntilDone:YES];  
  • 在当前线程执行操作
[self performSelector:@selector(run) withObject:nil];  

优缺点

1.优点:NSThread比其他两种多线程方案较轻量级,更直观地控制线程对象
2.缺点:需要自己管理线程的生命周期,线程同步。线程同步对数据的加锁会有一定的系统开销

NSOperation

使用NSOperation和NSOperationQueue进行多线程开发类似于 java 中的线程池,只要将一个NSOperation(实际开中需要使用其子类NSInvocationOperation、NSBlockOperation)放到NSOperationQueue这个队列中线程就会依次启动。NSOperationQueue负责管理、执行所有的NSOperation,在这个过程中可以更加容易的管理线程总数和控制线程之间的依赖关系。

NSOperation有两个常用子类用于创建线程操作:NSInvocationOperation和NSBlockOperation,两种方式本质没有区别,但是是后者使用Block形式进行代码组织,使用相对方便。

NSInvocationOperation *invocationOperation=[[NSInvocationOperation alloc]initWithTarget:self selector:@selector(loadImage) object:nil]; 
//创建完NSInvocationOperation对象并不会调用,它由一个start方法启动操作,但是注意如果直接调用start方法,则此操作会在主线程中调用,一般不会这么操作,而是添加到NSOperationQueue中
// [invocationOperation start]; 
//创建操作队列 
NSOperationQueue *operationQueue=[[NSOperationQueue alloc]init]; 
//注意添加到操作队后,队列会开启一个线程执行此操作    
[operationQueue addOperation:invocationOperation];


NSBlockOperation *blockOperation=[NSBlockOperation blockOperationWithBlock:^{
    [self loadImage];
}];

1.使用NSBlockOperation方法,所有的操作不必单独定义方法,同时解决了只能传递一个参数的问题。
2.调用主线程队列的addOperationWithBlock:方法进行UI更新,不用再定义一个参数实体(之前必须定义一个KCImageData解决只能传递一个参数的问题)。
3.使用NSOperation进行多线程开发可以设置最大并发线程,有效的对线程进行了控制(上面的代码运行起来你会发现打印当前进程时只有有限的线程被创建,如上面的代码设置最大线程数为5,则图片基本上是五个一次加载的)

GCD

// 获取默认优先级的全局并发dispatch queue
dispatch_queue_t queue1 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);

// 串行队列
dispatch_queue_t queue2 = dispatch_queue_create("test", NULL);

dispatch_async(queue1, ^{
    NSLog(@"开启了一个异步任务,当前线程:%@", [NSThread currentThread]);
});

dispatch_sync(queue2, ^{
    NSLog(@"开启了一个同步任务,当前线程:%@", [NSThread currentThread]);
});

并发队列同样是使用dispatch_queue_create()方法创建,只是最后一个参数指定为DISPATCH_QUEUE_CONCURRENT进行创建,但是在实际开发中我们通常不会重新创建一个并发队列而是使用dispatch_get_global_queue()方法取得一个全局的并发队列

  • 其他任务执行方法

GCD执行任务的方法并非只有简单的同步调用方法和异步调用方法,还有其他一些常用方法:

dispatch_apply():重复执行某个任务,但是注意这个方法没有办法异步执行(为了不阻塞线程可以使用dispatch_async()包装一下再执行)。
dispatch_once():单次执行一个任务,此方法中的任务只会执行一次,重复调用也没办法重复执行(单例模式中常用此方法)。
dispatch_time():延迟一定的时间后执行。
dispatch_barrier_async():使用此方法创建的任务首先会查看队列中有没有别的任务要执行,如果有,则会等待已有任务执行完毕再执行;同时在此方法后添加的任务必须等待此方法中任务执行后才能执行。(利用这个方法可以控制执行顺序,例如前面先加载最后一张图片的需求就可以先使用这个方法将最后一张图片加载的操作添加到队列,然后调用dispatch_async()添加其他图片加载任务)
dispatch_group_async():实现对任务分组管理,如果一组任务全部完成可以通过dispatch_group_notify()方法获得完成通知(需要定义dispatch_group_t作为分组标识)。

你可能感兴趣的:(iOS_多线程)