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

iOS多线程

2016-03-07 14:28 357 查看
iOS中多线程实现方案:



1.NSThread

1个NSThread对象就代表一条线程

创建线程:

NSThread *thread1 = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];


启动线程:

[thread1 start];


2 GCD(Grand Central Dispatch)

1)为多核的并行运算提出解决方案。

2)会自动管理线程的生命周期(创建线程,调度线程,销毁线程)。

3)只需要告诉GCD想要执行什么任务,不需要编写任何线程管理的代码。

步骤:

1)定制任务

2)将任务放到队列中,GCD会自动将队列中的任务取出,放到对应的线程中执行。FIFO原则

GCD中有2个用来执行任务的函数:

1)同步方式(只能在当前的线路中执行任务,不具备开启新线程的能力)

dispatch_sync(<#dispatch_queue_t queue#>, <#^(void)block#>);


2)异步方式(可以在新的线路中执行任务,具备开启新线程的能力)

dispatch_async(<#dispatch_queue_t queue#>, <#^(void)block#>);


GCD队列分为两大类:

1)并发队列(Concurrent Dispatch Queue)

可以让多个任务并发(同时)执行(自动开启多个线程同时执行任务)

只有在异步方式“dispatch_async”下才有效。

2)串行队列(Serial Dispathc Queue)

让任务一个接一个的执行

// 1.获得全局的并发队列:
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// 并发队列可选择的优先级:
#define DISPATCH_QUEUE_PRIORITY_HIGH 2
#define DISPATCH_QUEUE_PRIORITY_DEFAULT 0
#define DISPATCH_QUEUE_PRIORITY_LOW (-2)
#define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN


// 2.将任务加到队列中,异步方式执行(可创建子线程)
dispatch_async(queue, ^{

// 执行的任务

});


// 创建串行队列
dispatch_queue_t queue2 = dispatch_queue_create("name", NULL);
// 非ARC需要手动释放
dispatch_release(queue2);


// 获得主队列
dispatch_queue_t mainQueue = dispatch_get_main_queue();




注意:使用sync向当前串行队列中添加任务,会卡住当前的串行队列。

因为当前任务或者方法已经在主队列中,在同步(sync)方式下,仍往该队列中添加任务,那么势必等当前方法执行完之后,才能执行新添加的任务,而新添加的任务不执行,当前方法也不会往下继续执行完。所以会卡住。

2.1 GCD进程间通讯:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

// 子线程执行一些比较耗时的操作
// ...

dispatch_async(dispatch_get_main_queue(), ^{

// 回到主线程,执行一些UI相关的操作
// ...

});
});


2.2 利用GCD执行延迟操作:

不会卡住dispatch_after之后的操作,仍继续往下执行,等时间到了再回头执行里面的操作

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{

// 操作...

});


2.3 利用GCD控制代码执行的次数

static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{

// 只执行一次的操作
// ...

});


2.4 将读取/写入操作放到一个新建的串行队列中同步执行,可以代替同步锁,保证数据同步。

由于多个getter方法可以并发执行,而getter方法与setter方法间不能并发执行,利用这个特点,可以将读取和写入操作都放到一个“全局并发队列中”。

但是,为了保证并发队列中的读取/写入操作不是随时执行的,可以利用GCD的“barrier”功能。

在队列中,栅栏块必须单独执行,不能与其他块并行

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

// 虽然是并发队列,但“栅栏块”中的操作必须单独执行
dispatch_barrier_sync(queue, ^{

// 写入操作...
});


3.NSOperation

NSOperation和NSOperationQueue实现多线程的步骤

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

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

3)系统会自动将NSOperationQueue中的NSOperation取出来

4)将取出的NSOperation封装的操作放到一条新线程中执行

// 1.将操作封装到NSOperation对象中
NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{

// 执行的操作...

}];
[operation1 addExecutionBlock:^{
// 执行完任务1后要执行的操作
}];

// 2.创建队列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
// NSOperationQueue *queue2 = [NSOperationQueue mainQueue];(主队列)

// 3.添加操作到队列中
[queue addOperation:operation1];


3.1设置最大并发数

queue.maxConcurrentOperationCount = 2;


3.2操作依赖关系

NSOperation之间可以设置依赖来保证执行次序

如:一定要当操作A完成之后才可以执行B操作

NSBlockOperation *operationA = [NSBlockOperation blockOperationWithBlock:^{

// A执行的操作...
}];

NSBlockOperation *operationB = [NSBlockOperation blockOperationWithBlock:^{

// B执行的操作...
}];

// 操作B依赖于操作A
[operationB addDependency:operationA];


3.3取消队列的所有操作

[queue cancelAllOperations];


3.4暂停/恢复

-(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
// 开始拖拽时暂停/恢复操作
[queue setSuspended:YES]; // or NO
}


使用NSOperation及NSOperationQueue的好处:

1)便于取消操作。在任务运
9cb2
行之前,可以在NSOperation对象上调用cancel方法,该方法会设置对象内的标志位,表明此任务不需要执行。

2)指定操作间的依赖关系。使特定的操作必须在另外一个操作顺利执行完后执行。

3)通过KVO监控NSOperation对象的属性,可以在某个任务变更其状态时得到通知。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: