iOS多线程编程总结

丁灿
2023-12-01

摘录:http://www.cnblogs.com/mjios/archive/2013/04/18/3029309.html
http://blog.csdn.net/totogo2010/article/details/8010231

简介

iOS有三种多线程编程的技术,分别是:
1.、NSThread :这种方法需要管理线程的生命周期、同步、加锁问题,会导致一定的性能开销
2、Cocoa NSOperation :是基于OC实现的。NSOperation以面向对象的方式封装了需要执行的操作,然后可以将这个操作放到一个NSOperationQueue中去异步执行。不必关心线程管理、同步等问题。
3、GCD 全称:Grand Central Dispatch,简称GCD,iOS4才开始支持,是纯C语言的API。自iPad2开始,苹果设备开始有了双核CPU,为了充分利用这2个核,GCD提供了一些新特性来支持多核并行编程

1.NSThread

一个NSThread实例就代表着一条线程

创建

- (id)initWithTarget:(id)target selector:(SEL)selector object:(id)argument
+ (void)detachNewThreadSelector:(SEL)aSelector toTarget:(id)aTarget withObject:(id)anArgument

参数说明:
selector :线程执行的方法,这个selector只能有一个参数,而且不能有返回值。
target :selector消息发送的对象
argument:传输给target的唯一参数,也可以是nil
第一种方式会直接创建线程并且开始运行线程,第二种方式是先创建线程对象,然后再运行线程操作,在运行线程操作前可以设置线程的优先级等线程信息

例子:

// 初始化线程
2 NSThread *thread = [[[NSThread alloc] initWithTarget:self selector:@selector(run:) object:@"userinfo"] autorelease];
3 // 开启线程
4 [thread start];

run:方法

- (void)run:(NSString *)string {
     NSThread *current = [NSThread currentThread];
    NSLog(@"执行了run:方法-参数:%@,当前线程:%@", string, current);
 }
//结果
执行了run:方法-参数:userinfo,当前线程:<NSThread: 0x889e8d0>{name = (null), num = 3}

同步锁

创建锁可使用

NSLock *theLock = [[NSLock alloc] init]; 

已上面例子,对run:加锁

- (void)run:(NSString *)string {
    [theLock lock];
     NSThread *current = [NSThread currentThread];
    NSLog(@"执行了run:方法-参数:%@,当前线程:%@", string, current);
     [theLock unlock];
 }

还有其他的一些锁对象,比如:循环锁NSRecursiveLock,条件锁NSConditionLock,分布式锁NSDistributedLock等等

2、NSOperation

(1).思路:

1> 先将需要执行的操作封装到一个NSOperation对象中

2> 然后将NSOperation对象添加到NSOperationQueue中

3> 系统会自动将NSOperation中封装的操作放到一条新线程中执行

在此过程中,我们根本不用考虑线程的生命周期、同步、加锁等问题

(2).创建

默认情况下,NSOperation并不具备封装操作的能力,必须使用它的子类,使用NSOperation子类的方式有3种:

1> NSInvocationOperation

2> NSBlockOperation

3> 自定义子类继承NSOperation,实现内部相应的方法

(3).使用

NSInvocationOperation例子:

NSInvocationOperation *operation = [[[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run:) object:@"userinfo"] autorelease];  

NSOperationQueue *queue = [[NSOperationQueue alloc]init];  
[queue addOperation:operation];  

NSBlockOperation例子:

NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^(){
    NSLog(@"执行了一个新的操作");
}];

NSOperationQueue *queue = [[NSOperationQueue alloc]init];  
[queue addOperation:operation];  

若要并发执行多个任务,可使用NSBlockOperationaddExecutionBlock:方法添加了新的操作

[operation addExecutionBlock:^() {
   NSLog(@"又执行了1个新的操作,线程:%@", [NSThread currentThread]);
  }];

自定义NSOperation:
如果NSInvocationOperation和NSBlockOperation不能满足需求,我们可以直接新建子类继承NSOperation,并添加任何需要执行的操作。如果只是简单地自定义NSOperation,只需要重载-(void)main这个方法,在这个方法里面添加需要执行的操作。

注意:如果创建NSOperation后直接使用[operation start]; 执行线程还是会在当前线程同步执行操作,并没有异步执行

(4).取消操作

operation开始执行之后, 默认会一直执行操作直到完成,我们也可以调用cancel方法中途取消操作

[operation cancel];

(5).其他

如何控制线程池中的线程数?
队列里可以加入很多个NSOperation, 可以把NSOperationQueue看作一个线程池,可往线程池中添加操作(NSOperation)到队列中。线程池中的线程可看作消费者,从队列中取走操作,并执行它。
通过下面的代码设置:

[queue setMaxConcurrentOperationCount:5];

线程池中的线程数,也就是并发操作数。默认情况下是-1,-1表示没有限制,这样会同时运行队列中的全部的操作。

3.GCD

GCD的工作原理是:让程序平行排队的特定任务,根据可用的处理资源,安排他们在任何可用的处理器核心上执行任务。
一个任务可以是一个函数(function)或者是一个block。 GCD的底层依然是用线程实现,不过这样可以让程序员不用关注实现的细节。

(1).队列

GCD 是异步任务的技术之一,开发者可以用它将自定义的任务(task)追加到适当的派发队列(dispatch queue),就能生成必要的线程并执行任务。
在 GCD 中有三种队列:主队列(main queue)、全局队列(global queue)、用户队列(user-created queue)。
*全局队列是并发队列,即队列中的任务(task)执行顺序和进入队列的顺序无关;
主队列是串行队列,队列中的任务按FIFO(first input first output,先进先出)的顺序执行。
用户队列是用户自己创建的队列,可创建串行的也可以创建并行的
*

队列创建
全局队列(global queue):

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

第一个参数用于指定优先级,分别使用DISPATCH_QUEUE_PRIORITY_HIGH和DISPATCH_QUEUE_PRIORITY_LOW两个常量来获取高和低优先级的两个queue;第二个参数目前未使用到,默认0即可

主队列(main queue):

dispatch_queue_t  queue =dispatch_get_main_queue();//获取主线程队列

用户队列(user-created queue):

dispatch_queue_t serialQueue = dispatch_queue_create("cn.itcast.queue", NULL); //串行队列

dispatch_queue_t concurrentQueue = dispatch_queue_create("cn.itcast.queue",  DISPATCH_QUEUE_CONCURRENT); //并行队列

(2).派发

a.同步派发dispatch_sync
使用例子:

dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{  
    // 耗时的操作  
});  

同步派发,执行时,会阻塞调用它的线程,然后执行block的内容,执行完成才能继续往下执行。
注意:不用在主线程中,将任务同步派发到主线程队列,会造成死锁。

b.异步派发dispatch_async
使用例子:

dispatch_async(dispatch_get_main_queue(), ^{  
        // 更新界面  
});

异步派发,执行时,不会阻塞调用它的线程,直接执行block内容。

c.其他
dispatch_group_async:可以实现监听一组任务是否完成,完成后得到通知执行其他的操作。这个方法很有用,比如你执行三个下载任务,当三个任务都下载完成后你才通知界面说完成的了。
例子:

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);  
dispatch_group_t group = dispatch_group_create();  
dispatch_group_async(group, queue, ^{  
    [NSThread sleepForTimeInterval:1];  
    NSLog(@"group1");  
});  
dispatch_group_async(group, queue, ^{  
    [NSThread sleepForTimeInterval:2];  
    NSLog(@"group2");  
});  
dispatch_group_async(group, queue, ^{  
    [NSThread sleepForTimeInterval:3];  
    NSLog(@"group3");  
});  
dispatch_group_notify(group, dispatch_get_main_queue(), ^{  
    NSLog(@"updateUi");  
});  
dispatch_release(group);  

dispatch_barrier_async:是在前面的任务执行结束后它才执行,而且它后面的任务等它执行完成之后才会执行。

void dispatch_barrier_async( dispatch_queue_t queue, dispatch_block_t block);

其中,queue必须是用户通过dispatch_queue_create创建的并行队列。如:dispatch_queue_create("myqueue", DISPATCH_QUEUE_CONCURRENT);

(3)总结:

在使用GCD中,派发方式决定了改任务执行时,是否会阻塞调用线程。而执行的队列决定了该任务是串行执行还是并发执行。

 类似资料: