IOS开发-多线程编程技术(Thread、Cocoa operations、GCD)

版权所有,禁止匿名转载;禁止商业使用。

线程的定义:


每个正在系统上运行的程序都是一个进程。每个进程包含一到多个线程。进程也可能是整个程序或者是部分程序的动态执行。线程是一组指令的集合,或者是程序的特殊段,它可以在程序里独立执行。也可以把它理解为代码运行的上下文。所以线程基本上是轻量级的进程,它负责在单个程序里执行多任务。通常由操作系统负责多个线程的调度和执行。

转自百度百科: 多线程


IOS支持的多线程技术:


一、Thread:


1)显式创建线程:NSThreed


2)隐式创建线程:NSObject


二、Cocoa operations:


NSOperation类是一个抽象类,因为我们必须使用它的两个子类。


1)NSInvocationOperation


2)NSBlockOperation


————————————————————————————


3)NSOperationQueue(继承于NSObject)


三、Grand Central Dispatch (GCD):


1)GCD的创建


2)重复执行线程:dispatch_apply


3)操作队列:dispatch_queue_create


4)GCD群组通知:dispatch_group_t


5)GCD实现计时器


一、Thread


我们可以使用NSTherad或NSObject类去调用:


1)显式创建线程:NSThread


创建NSThread有两个办法


1.1)创建之后需要使用start方法,才会执行方法:


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

1.2)创建并马上执行方法:

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

2)隐式创建线程:NSObject


我们也可以使用NSObject类的方法直接调用方法

[self performSelectorInBackground:@selector(threadAlloc) withObject:nil];

NSThread相关属性及方法:


// 获取/设置线程的名字
@property (copy) NSString *name NS_AVAILABLE(10_5, 2_0);
/**
 *  获取当前线程的线程对象
 *
 *  通过这个属性可以查看当前线程是第几条线程,主线程为1。
 *  可以看到当前线程的序号及名字,主线程的序号为1,依次叠加。
 */
+ (NSThread *)currentThread;
// 线程休眠(秒)
+ (void)sleepForTimeInterval:(NSTimeInterval)ti;
// 线程休眠,指定具体什么时间休眠
+ (void)sleepUntilDate:(NSDate *)date;
// 退出线程 
// 注意:这里会把线程对象销毁!销毁后就不能再次启动线程,否则程序会崩溃。
+ (void)exit;

二、Cocoa operations


1)NSInvocationOperation


// 创建线程任务
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
// 线程A
NSInvocationOperation *operation = [[NSInvocationOperation alloc]
  initWithTarget:self
  selector:@selector(operation1)
  object:nil];
// 线程B
NSInvocationOperation *operation2 = [[NSInvocationOperation alloc]
  initWithTarget:self
  selector:@selector(operation2)
  object:nil];
// 把线程A/B添加至队列
[queue addOperations:@[operation, operation2] waitUntilFinished:YES];

必须使用addOperations:方法把线程添加至队列,不然线程不会执行。或者,你也可以使用addOperation:方法添加单个线程。


2)NSBlockOperation


举个简单的使用列子介绍,都写了备注,就不再说明了:


// 创建线程任务
NSBlockOperation *blockOperation = [NSBlockOperation
               blockOperationWithBlock:^{
                 NSLog(@"one - %@", [NSThread currentThread]);
               }];;
// 添加新的操作
[blockOperation addExecutionBlock:^{
  NSLog(@"two - %@", [NSThread currentThread]);
}];
// 添加新的操作
[blockOperation addExecutionBlock:^{
  NSLog(@"three - %@", [NSThread currentThread]);
}];
// 执行线程任务
[blockOperation start];
3)NSOperationQueue
这里介绍一下NSOperation的依赖关系,依赖关系会影响线程执行的顺序:
// 创建操作队列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
// 线程A
NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
  NSLog(@"op1");
  [NSThread sleepForTimeInterval:2];
}];
// 线程B
NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
  NSLog(@"op2");
}];
// 线程C
NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
  NSLog(@"op3");
  [NSThread sleepForTimeInterval:2];
}];
// 线程B依赖线程C,也就是等线程C执行完之后才会执行线程B
[op2 addDependency:op3];
// 线程C依赖线程A,同上,只不过依赖对象改成了线程A
[op3 addDependency:op1];
// 为队列添加线程
[queue addOperation:op1];
[queue addOperation:op2];
[queue addOperation:op3];

注意:依赖关系可以多重依赖,但不要建立循环依赖。


在NSOperationQueue类中,我们可以使用cancelAllOperations方法取消所有的线程。这里需要说明一下,不是执行cancelAllOperations方法时就会马上取消,是等当前队列执行完,下面的队列不会再执行。


NSOperation方法及属性:


// 设置线程的最大并发数
@property NSInteger maxConcurrentOperationCount;
// 线程完成后调用的Block
@property (copy) void (^completionBlock)(void);
// 取消线程
- (void)cancel;

只列举上面那些,其它的方法就不全列出来了。


三、Grand Central Dispatch (GCD)


1)GCD的创建:


dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    NSLog(@"线程 - %@", [NSThread currentThread]);
});

GCD也可以创建同步的线程,只需要把async改成sync即可。


2)重复执行线程:dispatch_apply


以下代码会执行4次:


dispatch_apply(4, DISPATCH_QUEUE_PRIORITY_DEFAULT, ^(size_t index) {
    // index则为执行的次数 0开始递增
    NSLog(@"one - %ld", index);
});

index参数为执行的次数,0开始递增


3)操作队列:dispatch_queue_create


// 创建队列
// 第一个参数是“字符串标识”,第二个参数是可选的,可以是NULL
dispatch_queue_t queue = dispatch_queue_create("com.garvey.post", NULL);
// 传入一个队列并执行队列(顺序执行)
dispatch_async(queue, ^{
  NSLog(@"aaa");
  [NSThread sleepForTimeInterval:2];
});
dispatch_async(queue, ^{
  NSLog(@"bbb");
  [NSThread sleepForTimeInterval:1];
});
dispatch_async(queue, ^{
  NSLog(@"ccc");
});

代码效果:以上会先执行aaa-》bbb-》ccc


4)GCD群组通知:dispatch_group_t


GCD的高级用法,等所有线程都完成工作后,再作通知。


// 创建群组
dispatch_group_t group = dispatch_group_create();
// 线程A
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
  NSLog(@"group1");
  [NSThread sleepForTimeInterval:2];
});
// 线程B
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
  NSLog(@"group2");
});
// 待群组里的线程都完成之后调用的通知
dispatch_group_notify(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
  NSLog(@"group success");
});

线程A和线程B都执行完之后,会调用通知打印group success。


5)GCD实现计时器


__block int time = 30;
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 1.0 * NSEC_PER_SEC, 0);
dispatch_source_set_event_handler(timer, ^{
  time--;
  NSLog(@"%d", time);
  if (time == 0) {
    dispatch_source_cancel(timer);
  }
});
dispatch_resume(timer);

代码效果:创建了一个计时器,计时器运行30秒,每过一秒会调用一次block,我们可以在block里面写代码。因为dispatch_source_t默认是挂起状态,因此我们使用时需要使用dispatch_resume方法先恢复,不然线程不会执行。


GCD方法及属性:


// 获取主线程
dispatch_get_main_queue()
// 创建队列:第一个参数是“字符串标识”,第二个参数是可选的,可以是NULL
dispatch_queue_t dispatch_queue_create(const char *label, dispatch_queue_attr_t attr);
// 创建异步调度队列
void dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
// 恢复队列
void dispatch_resume(dispatch_object_t object);
// 暂停队列
void dispatch_suspend(dispatch_object_t object);

本文参考:


iOS多线程开发


GCD的另一个用处是可以让程序在后台较长久的运行。


0 0