NSThread:
这套方案是经过苹果封装后的,并且完全面向对象的。所以你可以直接操控线程对象,非常直观和方便。但是,它的生命周期还是需要我们手动管理,所以这套方案也是偶尔用用,比如 [NSThread currentThread],它可以获取当前线程类,你就可以知道当前线程的各种属性,用于调试十分方便。下面来看看它的一些用法。
- 创建并启动
-先创建线程类,再启动
// 创建
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run:) object:nil];
// 启动
[thread start];
- 创建并自动启动
[NSThread detachNewThreadSelector:@selector(run:) toTarget:self withObject:nil];
- 使用 NSObject 的方法创建并自动启动
[self performSelectorInBackground:@selector(run:) withObject:nil];
GCD
Grand Central Dispatch,它是苹果为多核的并行运算提出的解决方案,所以会自动合理地利用更多的CPU内核(比如双核、四核),最重要的是它会自动管理线程的生命周期(创建线程、调度任务、销毁线程),完全不需要我们管理,我们只需要告诉干什么就行。同时它使用的也是 c语言,不过由于使用了 Block(Swift里叫做闭包),使得使用起来更加方便,而且灵活。
-
任务和队列
-
在 GCD中,加入了两个非常重要的概念: 任务 和 队列。
任务:即操作,你想要干什么,说白了就是一段代码,在 GCD 中就是一个 Block,所以添加任务十分方便。任务有两种执行方式: 同步执行 和 异步执行,他们之间的区别是 是否会创建新的线程。 -
同步(sync) 和 异步(async) 的主要区别在于会不会阻塞当前线程,直到 Block 中的任务执行完毕!
如果是 同步(sync) 操作,它会阻塞当前线程并等待 Block 中的任务执行完毕,然后当前线程才会继续往下运行。
如果是 异步(async)操作,当前线程会直接往下执行,它不会阻塞当前线程。 -
队列:用于存放任务。一共有两种队列, 串行队列 和 并行队列。
-
串行队列 中的任务会根据队列的定义 FIFO 的执行,一个进来执行完出去,下一个才会进来。
-
并行队列 根据队列的定义 FIFO 的执行,但它取出来一个就会放到别的线程,然后再取出来一个又放到另一个的线程。这样由于取的动作很快,忽略不计,看起来,所有的任务都是一起执行的。不过需要注意,GCD 会根据系统资源控制并行的数量,所以如果任务很多,它并不会让所有任务同时执行。
-
创建队列
主队列:这是一个特殊的 串行队列
它用于刷新 UI,任何需要刷新 UI 的工作都要在主队列执行,所以一般耗时的任务都要放到别的线程执行。
自己创建的队列:~~凡是自己创建的队列都是 串行队列
。其中第一个参数是标识符,用于 DEBUG 的时候标识唯一的队列,可以为空。大家可以看xcode的文档查看参数意义。 -
第二个参数用来表示创建的队列是串行的还是并行的,传入 DISPATCH_QUEUE_SERIAL 或 NULL表示创建串行队列。
传入 DISPATCH_QUEUE_CONCURRENT表示创建并行队列。
NSOperation和NSOperationQueue
- NSOperation 是苹果公司对 GCD 的封装,完全面向对象,所以使用起来更好理解。 大家可以看到 NSOperation 和 NSOperationQueue 分别对应 GCD 的 任务 和 队列 。操作步骤也很好理解:
- 将要执行的任务封装到一个 NSOperation 对象中。
- 将此任务添加到一个 NSOperationQueue 对象中。
添加任务
- NSOperation
只是一个抽象类,所以不能封装任务。但它有 2 个子类用于封装任务。分别是:NSInvocationOperation和NSBlockOperation- 创建一个 Operation 后,需要调用start
方法来启动任务,它会 默认在当前队列同步执行。当然你也可以在中途取消一个任务,只需要调用其cancel
- 创建一个 Operation 后,需要调用start
//1.创建NSInvocationOperation对象
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run) object:nil]; //2.开始执行
[operation start];
//1.创建NSBlockOperation对象 NSBlockOperation
*operation = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"%@", [NSThread currentThread]); }];
//2.开始任务
operation start];
线程同步
- 线程同步就是为了防止多个线程抢夺同一个资源造成的数据安全问题,所采取的一种措施
- 互斥锁 :给需要同步的代码块加一个互斥锁,就可以保证每次只有一个线程访问此代码块。
@synchronized(self) { //需要执行的代码块}
- **同步执行** :我们可以使用多线程的知识,把多个线程都要执行此段代码添加到同一个串行队列,这样就实现了线程同步的概念。当然这里可以使用 GCD和 NSOperation 两种方案,我都写出来。
//GCD
//需要一个全局变量queue,要让所有线程的这个操作都加到一个queue中
dispatch_sync(queue, ^{
NSInteger ticket = lastTicket;
[NSThread sleepForTimeInterval:0.1];
NSLog(@"%ld - %@",ticket, [NSThread currentThread]);
ticket -= 1; lastTicket = ticket;
});
//NSOperation & NSOperationQueue
//重点:1. 全局的 NSOperationQueue, 所有的操作添加到同一个queue中
// 2. 设置 queue 的 maxConcurrentOperationCount 为 1
// 3. 如果后续操作需要Block中的结果,就需要调用每个操作的waitUntilFinished,阻塞当前线程,一直等到当前操作完成,才允许执行后面的。waitUntilFinished 要在添加到队列之后! NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
NSInteger ticket = lastTicket;
[NSThread sleepForTimeInterval:1];
NSLog(@"%ld - %@",ticket, [NSThread currentThread]);
ticket -= 1; lastTicket = ticket; }];
[queue addOperation:operation];
[operation waitUntilFinished]; //后续要做的事
延迟执行
延迟执行就是延时一段时间再执行某段代码。下面说一些常用方法。
perform
// 3秒后自动调用self的run:方法,并且传递参数:@"abc"
[self performSelector:@selector(run:) withObject:@"abc" afterDelay:3];
GCD
// 创建队列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// 设置延时,单位秒
double delay = 3;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay * NSEC_PER_SEC)), queue, ^{
// 3秒后需要执行的任务
});
NSTimer
[NSTimer scheduledTimerWithTimeInterval:3.0 target:self selector:@selector(run:) userInfo:@"abc" repeats:NO];
单例模式
@interface Tool : NSObject <NSCopying>
+(instancetype)sharedTool;
@end
@implementation Toolstatic id _instance;
+(instancetype)sharedTool
{ static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [[Tool alloc] init];
});
return _instance;
}
@end
从其他线程回到主线程的方法
NSThread
//Objective-C
[self performSelectorOnMainThread:@selector(run) withObject:nil waitUntilDone:NO];
GCD
dispatch_async(dispatch_get_main_queue(), ^{
});
NSOperationQueue
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
}];
网友评论