在之前的項目技術上,我們進行學習
1:創建入口按鈕
//第三種方式 GCD
UIButton *btn2 = [UIButton buttonWithType:UIButtonTypeCustom];
btn2.frame = CGRectMake(40, 250, 100, 40);
[btn2 setTitle:@"GCD串行" forState:UIControlStateNormal];
[btn2 setBackgroundColor:[UIColor blueColor]];
[btn2 addTarget:self action:@selector(click_GCD_serial) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:btn2];
2:在 click_GCD_serial 方法中測試
dispatch_get_main_queue
情況一 : 在主隊列中開啓異步線程
dispatch_async(dispatch_get_main_queue(), ^(){
/在主線程隊列中開啓異步任務
NSLog(@"開始子線程 :task1");
for (int i = 10; i <= 20 ; i ++) {
sleep(1);
NSLog(@"當前線程名稱:%@ ——%d",[NSThread currentThread].name,i);
}
});
dispatch_async(dispatch_get_main_queue(), ^(){
/在主線程隊列中開啓異步任務
NSLog(@"開始子線程 :task2");
for (int i = 20; i <= 30 ; i ++) {
sleep(1);
NSLog(@"當前線程名稱:%@ ——%d",[NSThread currentThread].name,i);
if (i == 30) {
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"回到主線程,task2");
});
}
}
});
dispatch_async(dispatch_get_main_queue(), ^(){
/在主線程隊列中開啓異步任務
NSLog(@"開始子線程 :task3");
for (int i = 30; i <= 40 ; i ++) {
sleep(1);
NSLog(@"當前線程名稱:%@ ——%d",[NSThread currentThread].name,i);
if (i == 40) {
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"回到主線程, task3");
});
}
}
});
執行結果:
根據結果我們分析出:
1:在主隊列中執行異步任務還是會堵塞主線程,
2:系統不會開啓新的線程來執行異步任務;
3:所有的異步任務都會在主線程中執行;
4:所有的異步任務按照順序依次執行;
5:充分證明主隊列是串行隊列;
情況一 : 在主隊列中開啓同步線程
細心的朋友可能發現了,爲什麼要使用異步任務和主隊列進行組合呢,如果是同步任務和主隊列會是什麼樣的結果呢?我們用代碼進行求證;
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"回到主線程");
});
執行結果:
程序直接crash。思考一下爲什麼?
總結:
在主隊列中開啓任務,任務只能是異步任務,否則系統就會崩潰。也就是說不能使用創建同步任務調用主隊列。
錯誤代碼:
//錯誤例子如下:
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"回到主線程");
});
應用自創建串行隊列
場景應用: 要求線程中的任務按照順序來執行,或者線程之前之前存在依賴關係。
情況一:如果隊列中的任務都是同步任務
dispatch_queue_t serial = dispatch_queue_create("queue.costom", NULL); //創建串行隊列
dispatch_sync(serial, ^{
//在主線程隊列中開啓同步任務
NSLog(@"開始子線程 :task4");
for (int i = 40; i <= 50 ; i ++) {
sleep(1);
NSLog(@"當前線程名稱:%@ ——%d",[NSThread currentThread].name,i);
if (i == 50) {
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"回到主線程, task4");
});
}
}
});
dispatch_sync(serial, ^{
//在主線程隊列中開啓同步任務
NSLog(@"開始子線程 :task5");
for (int i = 50; i <= 60 ; i ++) {
sleep(1);
NSLog(@"當前線程名稱:%@ ——%d",[NSThread currentThread].name,i);
if (i == 60) {
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"回到主線程, task5");
});
}
}
});
dispatch_sync(serial, ^{
//在主線程隊列中開啓同步任務
NSLog(@"開始子線程 :task6");
for (int i = 60; i <= 70 ; i ++) {
sleep(1);
NSLog(@"當前線程名稱:%@ ——%d",[NSThread currentThread].name,i);
if (i == 70) {
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"回到主線程, task6");
});
}
}
});
執行結果:
結果分析:
1:會堵塞主線程;
2:不會開啓新線程;
3:在主線程中執行任務,會堵塞主線程;
4:任務會按照順序依次執行;
情況二 : 如果隊列中的任務都是異步任務
dispatch_queue_t serial = dispatch_queue_create("queue.costom", NULL); //創建串行隊列
dispatch_async(serial, ^{
//在主線程隊列中開啓同步任務
NSLog(@"開始子線程 :task4");
for (int i = 40; i <= 50 ; i ++) {
sleep(1);
NSLog(@"當前線程名稱:%@ ——%d",[NSThread currentThread].name,i);
if (i == 50) {
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"回到主線程, task4");
});
}
}
});
dispatch_async(serial, ^{
//在主線程隊列中開啓同步任務
NSLog(@"開始子線程 :task5");
for (int i = 50; i <= 60 ; i ++) {
sleep(1);
NSLog(@"當前線程名稱:%@ ——%d",[NSThread currentThread].name,i);
if (i == 60) {
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"回到主線程, task5");
});
}
}
});
dispatch_async(serial, ^{
//在主線程隊列中開啓同步任務
NSLog(@"開始子線程 :task6");
for (int i = 60; i <= 70 ; i ++) {
sleep(1);
NSLog(@"當前線程名稱:%@ ——%d",[NSThread currentThread].name,i);
if (i == 70) {
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"回到主線程, task6");
});
}
}
});
執行結果:
日誌分析:
1:不會堵塞主線程
2:會開啓一個子線程,所有的異步任務都在該線程內執行;
3:在子線程中的任務會按照順序依次執行
情況三:如果隊列中的任務有同步任務和異步任務
dispatch_queue_t serial = dispatch_queue_create("queue.costom", NULL); //創建串行隊列
dispatch_async(serial, ^{
//在主線程隊列中開啓同步任務
NSLog(@"開始子線程 :task4");
for (int i = 40; i <= 50 ; i ++) {
sleep(1);
NSLog(@"當前線程名稱:%@ ——%d",[NSThread currentThread].name,i);
// if (i == 50) {
// dispatch_async(dispatch_get_main_queue(), ^{
// NSLog(@"回到主線程, task4");
// });
// }
}
});
dispatch_sync(serial, ^{
//在主線程隊列中開啓同步任務
NSLog(@"開始子線程 :task5");
for (int i = 50; i <= 60 ; i ++) {
sleep(1);
NSLog(@"當前線程名稱:%@ ——%d",[NSThread currentThread].name,i);
// if (i == 60) {
// dispatch_async(dispatch_get_main_queue(), ^{
// NSLog(@"回到主線程, task5");
// });
// }
}
});
dispatch_async(serial, ^{
//在主線程隊列中開啓同步任務
NSLog(@"開始子線程 :task6");
for (int i = 60; i <= 70 ; i ++) {
sleep(1);
NSLog(@"當前線程名稱:%@ ——%d",[NSThread currentThread].name,i);
// if (i == 70) {
// dispatch_async(dispatch_get_main_queue(), ^{
// NSLog(@"回到主線程, task6");
// });
// }
}
});
執行結果:
日誌分析:
1:同步還是會在主線程中執行,造成主線程堵塞
2:異步任務會開啓子線程,並且異步任務在子線程中執行,此時不會造成主線程的堵塞
3:無論是同步任務或者異步任務,所有任務都是按照順序執行
至此,對串行隊列的學習和演示結束,我們可以得出以下的總結:
1:只要是串行隊列,無論任務是同步或者異步,所有的任務都是要按照順序依次執行的;
2:如果任務是同步任務就會在主線程中直接依次執行, 堵塞主線程
3:如果任務是異步任務就會開闢子線程執行,但還是會按照順序依次執行,執行完成一個任務之後再執行下一項任務,不會堵塞主線程