您的位置:首页 > 移动开发 > IOS开发

iOS多线程编程总结

2016-02-26 16:10 549 查看
摘录:/article/4834699.html

/article/1389856.html

简介

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];


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

[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中,派发方式决定了改任务执行时,是否会阻塞调用线程。而执行的队列决定了该任务是串行执行还是并发执行。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: