(1)主隊列
主隊列是GCD自帶的一種特殊的串行隊列,放在主隊列中得任務(wù),都會放到主線程中執(zhí)行。
dispatch_get_main_queue()
下面主要研究一下在主隊列中的同步和異步問題:
<1>同步
- (void)viewDidLoad {
[superviewDidLoad];
NSLog(@"%@",[NSThreadcurrentThread]);
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"sync----%@",[NSThreadcurrentThread]);
});
NSLog(@"%@",[NSThreadcurrentThread]);
}
打印結(jié)果:

你可能會奇怪:為什么只有一條打印記錄?其實這里出現(xiàn)了死鎖,所以后面的打印,包括同步任務(wù)里面的打印都無法執(zhí)行,為什么會發(fā)生死鎖呢,關(guān)鍵問題出現(xiàn)在設(shè)置的dispatch_sync方法里面的第一個參數(shù),下面來分析一下。
首先,系統(tǒng)執(zhí)行時,肯定是從主線程執(zhí)行第一個打印,之后執(zhí)行到dispatch_sync方法,這是同步方法,這個方法第一個參數(shù)是dispatch_get_main_queue(),所以會將block的打印任務(wù)放到主隊列中等待執(zhí)行。此時,主線程阻塞在這,等待同步任務(wù)的執(zhí)行。但是,主隊列串行隊列,一個任務(wù)執(zhí)行結(jié)束才能取出下一個任務(wù)執(zhí)行,而此時當(dāng)前的任務(wù)被阻塞了,無法結(jié)束,所以后一個任務(wù)(即剛剛添加的同步任務(wù))必須等待前一個任務(wù)結(jié)束后才能執(zhí)行。此時,主線程等待著同步任務(wù)執(zhí)行結(jié)束返回,而同步任務(wù)等待著主隊列的前一個任務(wù)(即當(dāng)前被阻塞的任務(wù))執(zhí)行結(jié)束后再執(zhí)行。所以出現(xiàn)了死鎖的現(xiàn)象。我們應(yīng)該盡量避免這種情況的發(fā)生。那么如果換成dispatch_async方法,是否就不會出現(xiàn)死鎖了呢?
<2>異步
- (void)viewDidLoad {
[superviewDidLoad];
NSLog(@"%@",[NSThreadcurrentThread]);
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"async----%@",[NSThreadcurrentThread]);
});
NSLog(@"%@",[NSThreadcurrentThread]);
}
打印結(jié)果:

顯然,這種情況下,所有的打印都能完成,簡單分析一下:主線程首先執(zhí)行第一個打印,執(zhí)行到dispatch_async方法時,往主隊列添加了一個異步任務(wù),此時并不阻塞主線程,主線程立刻返回執(zhí)行后面的打印。主線程當(dāng)前的任務(wù)完成了,然后從主隊列取出下一個任務(wù)(剛剛添加的異步任務(wù))來執(zhí)行,完成打印async—-。所以不會出現(xiàn)死鎖現(xiàn)象。
(2)全局隊列
dispatch_get_global_queue(longidentifier,unsignedlongflags)
第一個參數(shù)identifier: 在ios7中代表隊列優(yōu)先級(priority),在ios8及以后代表服務(wù)質(zhì)量(A quality of service),一般設(shè)置為DISPATCH_QUEUE_PRIORITY_DEFAULT即可。
兩者的對應(yīng)關(guān)系如下:
DISPATCH_QUEUE_PRIORITY_HIGH: QOS_CLASS_USER_INITIATED
DISPATCH_QUEUE_PRIORITY_DEFAULT: QOS_CLASS_DEFAULT
DISPATCH_QUEUE_PRIORITY_LOW: QOS_CLASS_UTILITY
DISPATCH_QUEUE_PRIORITY_BACKGROUND: QOS_CLASS_BACKGROUND
第二個參數(shù)flags:保留參數(shù),以便以后使用,一般傳0即可。
在全局隊列中,同步任務(wù)是否也會發(fā)生死鎖現(xiàn)象呢?
<1>同步
- (void)viewDidLoad {
[superviewDidLoad];
NSLog(@"%@",[NSThreadcurrentThread]);
dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{
NSLog(@"sync----%@",[NSThreadcurrentThread]);
});
NSLog(@"%@",[NSThreadcurrentThread]);
}
打印結(jié)果:

從打印結(jié)果來看,并沒有死鎖現(xiàn)象,仔細(xì)分析一下:主線程先執(zhí)行第一句打印,然后執(zhí)行dispatch_sync方法,往全局隊列中添加一個同步任務(wù),此時主線程應(yīng)該阻塞住,等待全局隊列中同步任務(wù)的執(zhí)行完畢,而全局隊列dispatch_sync方法并不會創(chuàng)建新線程,那肯定需要在主線程執(zhí)行(上一篇的結(jié)論),可是主線程已經(jīng)阻塞了,所以按理說此時應(yīng)該發(fā)生死鎖,可是為什么從打印結(jié)果看它確實是在主線程執(zhí)行的同步任務(wù),而且并沒有發(fā)生死鎖現(xiàn)象呢?
對應(yīng)這個問題,我利用前面和上面的知識都無法解釋,我在網(wǎng)上查了很多,都沒有提到過這個問題,難道是我上面的分析有問題,按照上面的分析,那所有的同步方法,無論是自定義隊列還是全局隊列、主隊列,同步任務(wù)都會出現(xiàn)死鎖現(xiàn)象。難道我鉆了牛角尖。沒有找到中文的解釋,我去官方文檔是查,也一無所獲,最后我無意的點進(jìn)了dispatch_sync的源代碼中,在該方法上面的注釋中發(fā)現(xiàn)了這么一句話:As an optimization, dispatch_sync() invokes the block on the current thread when possible.大致意思是:蘋果系統(tǒng)內(nèi)部做了優(yōu)化,將所有的dispatch_sync()方法中block的執(zhí)行都放在當(dāng)前的線程中,在我們這里也就是主線程中。這也解釋了上一篇留下的一個問題:為什么所有的同步方法都在主線程中執(zhí)行 ?可是,這個解釋,好像并不能回答為什么這里沒有發(fā)生死鎖的問題?我也一直沒有找到合理的解釋,如果哪位有比較合理的解釋,麻煩給我留言。
我個人的猜測:是否會在需要執(zhí)行dispatch_sync()方法時,將當(dāng)前任務(wù)先掛起,只要能取出要執(zhí)行的任務(wù)來就讓主線程先執(zhí)行,之后再來執(zhí)行掛起任務(wù)。這個猜測似乎和主隊列同步方法發(fā)生死鎖的解釋不矛盾,主隊列中的任務(wù)只能前一個執(zhí)行完后一個才能取出來執(zhí)行,所以在主隊列中后面的同步任務(wù)無法取出來,自然會發(fā)生死鎖。而全局隊列中,同步任務(wù)就是最前面的任務(wù),所以能取出來,所以可以由主線程來執(zhí)行,執(zhí)行后主線程可以返回執(zhí)行后面的操作。
轉(zhuǎn)載自feisongfs