同步異步?jīng)Q定是否具備開(kāi)啟線(xiàn)程的能力
串行并行決定代碼執(zhí)行的先后順序
先看下這幾個(gè)場(chǎng)景,每個(gè)場(chǎng)景中的代碼執(zhí)行后會(huì)打印什么,為什么?
場(chǎng)景一:
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
[self test1];
}
-(void)test1{
// 主隊(duì)列 串行隊(duì)列
dispatch_queue_t queue = dispatch_get_main_queue();
NSLog(@"任務(wù)1");
// 同步任務(wù)
dispatch_sync(queue, ^{
NSLog(@"任務(wù)2");
});
NSLog(@"任務(wù)3");
}
@end
答案:會(huì)打印任務(wù)1,然后程序奔潰

原因:由于整個(gè)viewDidLoad方法是先加入到主隊(duì)列中的,然后將viewDidLoad方法中的代碼從隊(duì)列中取出來(lái)一步步執(zhí)行,當(dāng)執(zhí)行到dispatch_sync時(shí),就會(huì)將任務(wù)2的代碼加入到主隊(duì)列中,由于主隊(duì)列是串行隊(duì)列,所以必須要讓先從主隊(duì)列中取出來(lái)的viewDidLoad方法中的所有代碼執(zhí)行完才能取出后面加入到主隊(duì)列中的任務(wù)2代碼來(lái)執(zhí)行,但dispatch_sync同步任務(wù)的特點(diǎn)是立即要在當(dāng)前線(xiàn)程也就是主線(xiàn)程中執(zhí)行任務(wù)2中的代碼,這樣就形成了互相等待的僵局,這就是死鎖!
場(chǎng)景二:
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
[self test1];
}
-(void)test1{
// 主隊(duì)列 串行隊(duì)列
dispatch_queue_t queue = dispatch_get_main_queue();
NSLog(@"任務(wù)1");
// 異步任務(wù)
dispatch_async(queue, ^{
NSLog(@"任務(wù)2");
});
NSLog(@"任務(wù)3");
}
@end
答案:結(jié)果打印任務(wù)1、任務(wù)3、任務(wù)2,程序正常運(yùn)行

原因:在執(zhí)行主隊(duì)列中的viewDidLoad方法時(shí),碰到dispatch_async時(shí)也會(huì)將任務(wù)2中的代碼加入到主隊(duì)列中,但不同的是dispatch_async并不要求立馬執(zhí)行,可以延后執(zhí)行,這樣viewDidLoad方法執(zhí)行完后再?gòu)闹麝?duì)列中取出剛加入的任務(wù)2代碼,就不會(huì)造成互相等待的情況了
場(chǎng)景三:
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
[self test1];
}
-(void)test1{
// 手動(dòng)創(chuàng)建的串行隊(duì)列
dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL);
NSLog(@"任務(wù)1");
// 同步任務(wù)
dispatch_sync(queue, ^{
NSLog(@"任務(wù)2");
});
NSLog(@"任務(wù)3");
}
答案:結(jié)果打印任務(wù)1、任務(wù)2、任務(wù)3,程序正常運(yùn)行

原因:在執(zhí)行主隊(duì)列中的viewDidLoad方法時(shí),碰到dispatch_sync時(shí)就會(huì)將任務(wù)2中的代碼加入到手動(dòng)創(chuàng)建的串行隊(duì)列中,同步任務(wù)會(huì)讓任務(wù)中代碼立即執(zhí)行,由于任務(wù)2中的代碼是在其他的串行隊(duì)列中執(zhí)行,和主線(xiàn)程沒(méi)有關(guān)系,所以就優(yōu)先執(zhí)行任務(wù)2中的代碼,最后執(zhí)行任務(wù)3
場(chǎng)景四:
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
[self test1];
}
-(void)test1{
// 手動(dòng)創(chuàng)建的串行隊(duì)列
dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL);
NSLog(@"任務(wù)1");
// 異步任務(wù)
dispatch_async(queue, ^{
NSLog(@"任務(wù)2");
});
NSLog(@"任務(wù)3");
}
答案:結(jié)果打印任務(wù)1、任務(wù)2、任務(wù)3(或者任務(wù)1、任務(wù)3、任務(wù)2),程序正常運(yùn)行

原因:在執(zhí)行主隊(duì)列中的viewDidLoad方法時(shí),碰到dispatch_async時(shí)就會(huì)將任務(wù)2中的代碼加入到手動(dòng)創(chuàng)建的串行隊(duì)列中,由于任務(wù)2和任務(wù)3不在同一個(gè)隊(duì)列中,而且任務(wù)2又是異步執(zhí)行,會(huì)創(chuàng)建子線(xiàn)程,所以任務(wù)2和任務(wù)3是并發(fā)執(zhí)行的,因此打印結(jié)果會(huì)有兩種情況
場(chǎng)景五:
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
[self test1];
}
-(void)test1{
// 手動(dòng)創(chuàng)建的串行隊(duì)列
dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL);
NSLog(@"任務(wù)1");
// 異步任務(wù)
dispatch_async(queue, ^{ // block1
NSLog(@"任務(wù)2");
// 同步任務(wù)
dispatch_sync(queue, ^{ // block2
NSLog(@"任務(wù)3");
});
NSLog(@"任務(wù)4");
});
NSLog(@"任務(wù)5");
}
答案:結(jié)果打印任務(wù)1、任務(wù)2(或者任務(wù)1、任務(wù)5、任務(wù)2)程序奔潰,產(chǎn)生死鎖

原因:在執(zhí)行主隊(duì)列中的viewDidLoad方法時(shí),碰到dispatch_async時(shí)就會(huì)將block1中的代碼加入到手動(dòng)創(chuàng)建的串行隊(duì)列中,由于任務(wù)2和任務(wù)5不在同一個(gè)隊(duì)列中,而且任務(wù)2又是異步執(zhí)行,會(huì)創(chuàng)建子線(xiàn)程,所以任務(wù)2和任務(wù)5是并發(fā)執(zhí)行的,因此打印結(jié)果會(huì)有兩種情況,當(dāng)block1在執(zhí)行任務(wù)2的時(shí)候,碰到dispatch_sync就會(huì)將block2加入到當(dāng)前串行隊(duì)列queue中,由于dispatch_sync是同步任務(wù),需要立即執(zhí)行blcok2中的代碼,但queue是串行隊(duì)列,需要將已經(jīng)取出來(lái)執(zhí)行的block1的代碼執(zhí)行完才能執(zhí)行串行隊(duì)列中的下一個(gè)任務(wù)也就是block2,這樣就互相等待造成死鎖!
結(jié)論:
正在執(zhí)行的代碼是從串行隊(duì)列中取出來(lái)的,而且再次向該串行隊(duì)列中加入同步任務(wù)就會(huì)造成死鎖!兩者缺一不可!
1.如果向該串行隊(duì)列中加入的是異步任務(wù)
2.如果將任務(wù)加入到其他隊(duì)列
3.如果將該串行隊(duì)列改為并發(fā)隊(duì)列這三種情況都不會(huì)產(chǎn)生死鎖!