什么是多线程?
同一时间内单核的CPU只能执行一个线程,多线程是CPU快速的在多个线程之前进行切换(调度),造成了多个线程同时执行的假象。
如果是多核CPU就真的可以同时处理多个线程了。
多线程目的是为了同步完成多项任务,通过提高系统的资源利用率来提高系统的效率。
开启线程需要消耗内存资源和性能。每一个纯种都需要分配系统内核空间和程序的内存空间。
线程和进程
进程是一个正在运行的应用程序,一个应用程序对应一个进程。应用程序是一个没有生命的实体,只有运行以后,才能称为一个活动的实体,也就是进程。
进程是操作系统分配资源的基本单元。进程在运行的过程中拥有独立的内在单元,一个进程崩溃后,不会对其他进程造成影响。
线程是独立运行和独立调度的基本单位。线程才是程序真正的执行单元负责代码的执行。一个进程可以有一个或多个线程,同一个进程的线程共享进程的内在资源。线程没有单独的地址空间,一个线程崩溃整个进程就会崩溃。
-
任务和队列
任务:执行操作
队列:用来存放任务 -
并行和并发
并行:充分利用计算机的多核,在多个纯种上同步进行
并发:在一条线程上通过快速切换,让人感觉在同步进行 -
同步和异步
同步:只能在当前线程中执行任务,会阻塞当前线程,不具备开启新线程的能力。
异步:可以在新纯种中执行任务, 开启新纯种的能力。 -
主线程特点
主线程会先执行主线程上的代码片段,然后才会去执行放在主队列中的任务。
iOS中多线程的几种方案
- Pthread是用C语言实现的,非常底层,在开发中很少用到。需要手动管理线程的生命周期(手动创建和销毁)。
- NSThread面向对象的,需要手动创建纯种,不需要手动销毁。子线程间通信很难。
NSThread * thread = [[NSThread alloc] initWithTarget:self selector:@selector(testWithObject:) object:@"test"];//有反回值,可以设置线程的优先级和名称
[thread start];//需要开启
[NSThread detachNewThreadSelector:@selector(testWithObject:) toTarget:self withObject:@"参数"];//没有返回值,自动开启
-
GCD C语言,充分利用了设备的多核,自动管理线程生命周期。比NSOperation效率更高。
dispatch_sync
会阻塞当前纯种,task不执行完毕,dispatch_sync
函数不返回。
dispatch_async
不会阻塞当前线程,不等待task执行,直接执行后面的代码。 -
NSOperation 基于gcd封装,更加面向对象,比gcd多了一些功能
可添加完成的代码块,在操作完成后执行。
添加操作之间的依赖关系,方便的控制执行顺序。
设定操作执行的优先级。
可以很方便的取消一个操作的执行。
使用 KVO 观察对操作执行状态的更改:isExecuteing、isFinished、isCancelled。
NSOperationQueue
操作队列,不同于GCD中的调度队列FIFO(先进先出)原则。
NSOperationQueue
操作队列中的任务的执行顺序,受到任务的isReady
状态和任务的队列优先级及依赖影响。
NSOperationQueue
有两种不同类型的队列:主队列和自定义队列。主队列在主纯种上运行,而自定义队列在后台执行。这两种队列中加入的任务都需要用NSOperation
的子类来表示。
//创建一个自定义队列
NSOperationQueue * customQueue = [[NSOperationQueue alloc] init];
//创建一个主队列
NSOperationQueue * mainQueue = [NSOperationQueue mainQueue];
https://www.jianshu.com/p/89b3edfb43ce
https://www.jianshu.com/p/4b1d77054b35
- 主队列异步任务
因为是在主队列添加任务,所以需要等1秒后才可以执行异步任务
dispatch_queue_t queue = dispatch_get_main_queue();
//异步任务1
dispatch_async(queue, ^{
//异步任务2
dispatch_async(queue, ^{
sleep(2);
NSLog(@"%@-------------1",[NSThread currentThread]);
});
NSLog(@"%@-------------2",[NSThread currentThread]);
//异步任务3
dispatch_async(queue, ^{
NSLog(@"%@------------3",[NSThread currentThread]);
});
});
sleep(1);
//1、向主队列中添加异步任务1
//2、等待1秒
//3、执行异步任务1
// 3.1、向主队列中添加异步任务2
// 3.2、输出2
// 3.3、向主队列中添加异步任务3
//4、执行异步任务2
// 4.1、等待2秒
// 4.2、输出1
//5、执行异步任务3
// 5.1、输出3
- 全局队列异步任务
因为全局队列是异步队列,所以添加后立即执行。
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//异步任务1
dispatch_async(queue, ^{
//异步任务2
dispatch_async(queue, ^{
sleep(2);
NSLog(@"%@-------------1",[NSThread currentThread]);
});
NSLog(@"%@-------------2",[NSThread currentThread]);
//异步任务3
dispatch_async(queue, ^{
NSLog(@"%@-------------3",[NSThread currentThread]);
});
});
sleep(1);
//1、向全局队列中添加异步任务1,并开始执行
//2、原线程等待1秒
//3、执行异步任务1
// 3.1、向全局队列中添加异步任务2,并开始执行
// 3.1.1、等待2秒,2秒后输出1
// 3.2、输出2
// 3.3、向全局队列中添加异步任务3,并开始执行
// 3.3.1、输出3
//
// 3.1.2、2秒已过,输出1
- NSOpertaionQueue是异步队列, maxConcurrentOperationCount = 1是为串行,大于1时为并发。
NSOperationQueue * opQueue = [[NSOperationQueue alloc] init];
opQueue.maxConcurrentOperationCount = 1;
//任务1
[opQueue addOperationWithBlock:^{
//任务2
[opQueue addOperationWithBlock:^{
sleep(1);
NSLog(@"%@-------------1",[NSThread currentThread]);
}];
NSLog(@"%@-------------2",[NSThread currentThread]);
//任务3
[opQueue addOperationWithBlock:^{
NSLog(@"%@-------------3",[NSThread currentThread]);
}];
}];
//opQueue.maxConcurrentOperationCount = 1; 运行步骤
//1、添加任务1到队列中
//2、执行任务1
// 2.1、添加任务2到队列中
// 2.2、输出2
// 2.3、添加任务3到队列中
// 2.4、执行任务2
// 2.4.1、等待1秒,1秒后输出1
// 2.4.2、1秒已过,输出1
// 2.5、执行任务3,
// 2.5.1、输出3
//opQueue.maxConcurrentOperationCount = 2; 运行步骤
//1、添加任务1到队列中
//2、执行任务1
// 2.1、添加任务2到队列中
// 2.2、执行任务2
// 2.2.1、等待1秒,1秒后输出1
// 2.3、输出2
// 2.4、添加任务3到队列中
// 2.5、执行任务3,
// 2.5.1、输出3
// 2.2.2、1秒已过,输出1
- 不管调用多少次都只执行一次的方法
static int methoedCount = 0;
- (void)onceMethed
{
@synchronized (self) {
if (methoedCount == 0) {
NSLog(@"只执行一次");
methoedCount = 1;
}
}
}
- (void)onceMethed2
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSLog(@"只执行一次");
});
}
- 在一定时间内不论调用多少次,只执行最后一次。
- (void)afterDelay2{
__block ViewController * vc = self;
//全局block用来保存要执行的方法及参数
self.clickBlock = ^ {
[vc test];
vc = nil;
};
NSLog(@"%@",self.clickBlock);
//判断tiemr是否存在,存在直接return。
if (self.timer){
return;
}
dispatch_async(dispatch_get_global_queue(0, 0), ^{
//创建定时器。
self.timer = [NSTimer timerWithTimeInterval:3 repeats:NO block:^(NSTimer * _Nonnull timer) {
//在指定的时间结束后,调用block
self.clickBlock();
//销毁timer
[self.timer invalidate];
self.timer = nil;
}];
[[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSDefaultRunLoopMode];
[[NSRunLoop currentRunLoop] run];
});
}
- 调用后开始计时,在timer时间内再次点击,重新计时。只调用最后一次。
- (void)afterDelay1{
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(block2) object:nil];
[self performSelector:@selector(block2) withObject:nil afterDelay:0.5];
}
网友评论