同步异步决定是否具备开启线程的能力
串行并行决定代码执行的先后顺序
先看下这几个场景,每个场景中的代码执行后会打印什么,为什么?
场景一:
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
[self test1];
}
-(void)test1{
// 主队列 串行队列
dispatch_queue_t queue = dispatch_get_main_queue();
NSLog(@"任务1");
// 同步任务
dispatch_sync(queue, ^{
NSLog(@"任务2");
});
NSLog(@"任务3");
}
@end
答案:会打印任务1,然后程序奔溃
截屏2020-07-06 14.23.24.png
原因:由于整个viewDidLoad方法是先加入到主队列中的,然后将viewDidLoad方法中的代码从队列中取出来一步步执行,当执行到dispatch_sync时,就会将任务2的代码加入到主队列中,由于主队列是串行队列,所以必须要让先从主队列中取出来的viewDidLoad方法中的所有代码执行完才能取出后面加入到主队列中的任务2代码来执行,但dispatch_sync同步任务的特点是立即要在当前线程也就是主线程中执行任务2中的代码,这样就形成了互相等待的僵局,这就是死锁!
场景二:
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
[self test1];
}
-(void)test1{
// 主队列 串行队列
dispatch_queue_t queue = dispatch_get_main_queue();
NSLog(@"任务1");
// 异步任务
dispatch_async(queue, ^{
NSLog(@"任务2");
});
NSLog(@"任务3");
}
@end
答案:结果打印任务1、任务3、任务2,程序正常运行
截屏2020-07-06 14.25.33.png
原因:在执行主队列中的viewDidLoad方法时,碰到dispatch_async时也会将任务2中的代码加入到主队列中,但不同的是dispatch_async并不要求立马执行,可以延后执行,这样viewDidLoad方法执行完后再从主队列中取出刚加入的任务2代码,就不会造成互相等待的情况了
场景三:
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
[self test1];
}
-(void)test1{
// 手动创建的串行队列
dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL);
NSLog(@"任务1");
// 同步任务
dispatch_sync(queue, ^{
NSLog(@"任务2");
});
NSLog(@"任务3");
}
答案:结果打印任务1、任务2、任务3,程序正常运行
截屏2020-07-06 14.38.29.png
原因:在执行主队列中的viewDidLoad方法时,碰到dispatch_sync时就会将任务2中的代码加入到手动创建的串行队列中,同步任务会让任务中代码立即执行,由于任务2中的代码是在其他的串行队列中执行,和主线程没有关系,所以就优先执行任务2中的代码,最后执行任务3
场景四:
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
[self test1];
}
-(void)test1{
// 手动创建的串行队列
dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL);
NSLog(@"任务1");
// 异步任务
dispatch_async(queue, ^{
NSLog(@"任务2");
});
NSLog(@"任务3");
}
答案:结果打印任务1、任务2、任务3(或者任务1、任务3、任务2),程序正常运行
截屏2020-07-06 14.46.20.png
原因:在执行主队列中的viewDidLoad方法时,碰到dispatch_async时就会将任务2中的代码加入到手动创建的串行队列中,由于任务2和任务3不在同一个队列中,而且任务2又是异步执行,会创建子线程,所以任务2和任务3是并发执行的,因此打印结果会有两种情况
场景五:
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
[self test1];
}
-(void)test1{
// 手动创建的串行队列
dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL);
NSLog(@"任务1");
// 异步任务
dispatch_async(queue, ^{ // block1
NSLog(@"任务2");
// 同步任务
dispatch_sync(queue, ^{ // block2
NSLog(@"任务3");
});
NSLog(@"任务4");
});
NSLog(@"任务5");
}
答案:结果打印任务1、任务2(或者任务1、任务5、任务2)程序奔溃,产生死锁
截屏2020-07-06 15.01.55.png
原因:在执行主队列中的viewDidLoad方法时,碰到dispatch_async时就会将block1中的代码加入到手动创建的串行队列中,由于任务2和任务5不在同一个队列中,而且任务2又是异步执行,会创建子线程,所以任务2和任务5是并发执行的,因此打印结果会有两种情况,当block1在执行任务2的时候,碰到dispatch_sync就会将block2加入到当前串行队列queue中,由于dispatch_sync是同步任务,需要立即执行blcok2中的代码,但queue是串行队列,需要将已经取出来执行的block1的代码执行完才能执行串行队列中的下一个任务也就是block2,这样就互相等待造成死锁!
结论:
正在执行的代码是从串行队列中取出来的,而且再次向该串行队列中加入同步任务就会造成死锁!两者缺一不可!
1.如果向该串行队列中加入的是异步任务
2.如果将任务加入到其他队列
3.如果将该串行队列改为并发队列这三种情况都不会产生死锁!
网友评论