概念解释:
同步和异步决定了要不要开启新的线程
同步:在当前线程中执行任务,不具备开启新线程的能力
异步:在新的线程中执行任务,具备开启新线程的能力
并发和串行决定了任务的执行方式
并发:多个任务并发(同时)执行
串行:一个任务执行完毕后,再执行下一个任务
通过GCD可获得的三种队列
1.全局并发队列
2.主队列(跟主线程相关联的队列)
3.自定义队列
三种队列通过同步、异步方式,实验下6种方式:
1.全局并发队列,同步方式
- (void)count{
for (int i = 0; i < 5; i++) {
NSLog(@"num:%d",i);
}
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
//获取全局队列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_sync(queue, ^{
NSLog(@"下载图片1---%@", [NSThread currentThread]);
[self count];
});
dispatch_sync(queue, ^{
NSLog(@"下载图片2---%@", [NSThread currentThread]);
[self count];
});
}
运行结果:
number = 1表示当前是主线程,因为是dispatch_sync同步方式往全局队列中添加的任务,可见并没有开启新的线程。
2.全局并发队列,异步方式
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
NSLog(@"下载图片3---%@", [NSThread currentThread]);
[self count];
});
dispatch_async(queue, ^{
NSLog(@"下载图片4---%@", [NSThread currentThread]);
[self count];
});
}
运行结果:
可以看到number =4,number = 3,意味着开启了两个子线程去完成任务,观察num:0 num:0 ,交替打印出num的值,可以理解为两个任务同时进行,即并行处理
3.主队列,同步方式
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
dispatch_queue_t queue = dispatch_get_main_queue();
dispatch_sync(queue, ^{
NSLog(@"下载图片1---%@", [NSThread currentThread]);
[self count];
});
dispatch_sync(queue, ^{
NSLog(@"下载图片2---%@", [NSThread currentThread]);
[self count];
});
}
这里运行,看起来并没有什么反应,也没有什么什么结果在Xcode上打印出来,为什么呢?这里涉及到串行队列中执行串行同步操作造成死锁的问题。
*首先大环境是主队列(主队列本质是串行队列 遵循FIFO),在主队列中,使用同步函数在主队列(相当于在相同的串行队列)末尾加入了任务。主队列 遇到了同步函数,准备继续往下执行程序,但是同步函数这时候也要执行,这意味着程序需要等待同步函数执行完成后才能继续。那么同步函数什么时候执行完成呢?同步函数需要等它自己block中的任务执行结束,而block种的任务什么时候执行结束呢?根据串行队列FIFO原则,要等待主队列中block这个任务前面所有的任务完成,而block任务是在主队列队尾,block前面的任务至少还有一个同步函数dispatch_sync()这个任务,所以block必须等待dispatch_sync()执行完。 那么问题来了,dispatch_sync()等待block执行完,block又在等待dispatch_sync()执行完,互相等待,这就造成死锁了。主要原因是主队列是串行队列。
4.主队列,异步方式
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
[self count];
dispatch_queue_t queue = dispatch_get_main_queue();
dispatch_async(queue, ^{
NSLog(@"下载图片3---%@", [NSThread currentThread]);
[self count];
});
dispatch_async(queue, ^{
NSLog(@"下载图片4---%@", [NSThread currentThread]);
[self count];
});
}
分析一下:
*异步方式开启,等主线程执行完操作,才处理主队列中的任务
*虽然是异步方式,但是number = 1,并没有开启新的线程
5.自创建串行队列,同步方式
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
dispatch_queue_t queue = dispatch_queue_create("myqueue", DISPATCH_QUEUE_SERIAL);
dispatch_sync(queue, ^{
NSLog(@"下载图片1---%@", [NSThread currentThread]);
[self count];
});
dispatch_sync(queue, ^{
NSLog(@"下载图片2---%@", [NSThread currentThread]);
[self count];
});
}
*同步方式,串行队列,没有开启新线程。
*由于同步函数不具备开启新线程的能力,所以就不列举同步函数执行并发队列的 例子了。
6.自创建并发队列,异步方式
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
dispatch_queue_t queue = dispatch_queue_create("myqueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_sync(queue, ^{
NSLog(@"下载图片1---%@", [NSThread currentThread]);
[self count];
});
dispatch_sync(queue, ^{
NSLog(@"下载图片2---%@", [NSThread currentThread]);
[self count];
});
}
*异步方式,观察number =3,number=4,意味着,开启了两个新的线程处理任务
*num打印的值来看,由于创建的并发队列,所以并行处理。类似例子1中的全局队列,同步方式。
小结
方式 | 全局队列 | 主队列 | 自创建队列 |
---|---|---|---|
同步 | 未开启新线程,串行执行任务 | 未开启新线程,串行执行任务 | 未开启新线程,串行执行任务 |
异步 | 开启新线程,并发执行任务 | 开启新线程,串行执行任务 | 未开启新线程,串行执行任务 |