相關(guān)文章:
iOS多線程之NSThread
iOS多線程之NSOperations
隊(duì)列
隊(duì)列 | Api | 備注 |
---|---|---|
主隊(duì)列(main queue) | dispatch_get_main_queue() |
串行隊(duì)列,可以操縱UI |
全局調(diào)度隊(duì)列(Global Dispatch Queues) | dispatch_get_global_queue() |
并行隊(duì)列,按照?qǐng)?zhí)行優(yōu)先級(jí),分成4種global queue:DISPATCH_QUEUE_PRIORITY_HIGH , DISPATCH_QUEUE_PRIORITY_DEFAULT , DISPATCH_QUEUE_PRIORITY_LOW , DISPATCH_QUEUE_PRIORITY_BACKGROUND
|
自創(chuàng)建隊(duì)列 | dispatch_queue_create() |
可以創(chuàng)建: 串行( DISPATCH_QUEUE_SERIAL )、并行( DISPATCH_QUEUE_CONCURRENT )隊(duì)列 |
并行隊(duì)列 | 串行隊(duì)列 |
---|---|
并行隊(duì)列
|
串行隊(duì)列
|
隊(duì)列和線程是兩個(gè)不同的概念。一個(gè)隊(duì)列可以有多個(gè)線程。每個(gè)隊(duì)列中的操作會(huì)在所屬的線程中運(yùn)行。舉個(gè)例子你創(chuàng)建一個(gè)并行隊(duì)列,然后添加三個(gè)操作到里面。隊(duì)列會(huì)發(fā)起三個(gè)單獨(dú)的線程,然后讓所有操作在各自的線程中并發(fā)運(yùn)行。
提交任務(wù)(block)到隊(duì)列(queue)
提交方式 | 備注 |
---|---|
dispatch_async (dispatch_queue_t queue, dispatch_block_t block) |
異步提交block到queue |
dispatch_sync (dispatch_queue_t queue, dispatch_block_t block) |
同步地提交工作并在返回前等待它完成 |
dispatch_after (dispatch_time_t when, dispatch_queue_t queue, dispatch_block_t block) |
異步提交block到queue,并且延遲執(zhí)行block,dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)) 表示3秒后 |
dispatch_barrier_async (dispatch_queue_t queue, dispatch_block_t block) |
異步提交block,但是該block被執(zhí)行時(shí),隊(duì)列中其它block不會(huì)被執(zhí)行,即barrier相當(dāng)于一個(gè)狹窄的通道 場(chǎng)景:多線程讀寫競(jìng)態(tài)資源,多個(gè)讀線程間可以并行,但讀寫、寫寫線程間只能串行,這時(shí)可以: 1)使用并發(fā)隊(duì)列(為了防止 barrier 特性影響其它線程,不要使用dispatch_get_global_queue ,而是使用dispatch_queue_create 來(lái)創(chuàng)建新隊(duì)列)2)使用 dispatch_barrier_async 添加寫block,保證隊(duì)列中寫block執(zhí)行時(shí)不會(huì)有其它讀寫block正在執(zhí)行 |
注意:
如果你調(diào)用 dispatch_sync 并放在你已運(yùn)行著的當(dāng)前串行隊(duì)列。這會(huì)導(dǎo)致死鎖,因?yàn)檎{(diào)用會(huì)一直等待直到 Block 完成,但 Block 不能完成(它甚至不會(huì)開(kāi)始!),直到當(dāng)前已經(jīng)存在的任務(wù)完成,而當(dāng)前任務(wù)無(wú)法完成!舉個(gè)例子:
@implementation ViewController1
- (void)viewDidLoad
{
[super viewDidLoad];
// dispatch_sync同步提交block到main隊(duì)列(當(dāng)前隊(duì)列)并**等待**block執(zhí)行完畢,而由于是串行隊(duì)列,block需要等待當(dāng)前任務(wù)執(zhí)行完畢,雙向等待造成死鎖。
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"hello world");
});
// 下面這條NSLog不會(huì)被執(zhí)行,因?yàn)榫€程已經(jīng)死鎖
NSLog(@"here");
@end
@implementation ViewController2
- (void)viewDidLoad
{
[super viewDidLoad];
// 創(chuàng)建一個(gè)并行隊(duì)列,,,,(*注意:*如果將*DISPATCH_QUEUE_CONCURRENT*修改成*DISPATCH_QUEUE_SERIAL*,即創(chuàng)建串行隊(duì)列,就會(huì)發(fā)生死鎖!!!)
dispatch_queue_t queue = dispatch_queue_create("abc", DISPATCH_QUEUE_CONCURRENT);
dispatch_sync(queue, ^{
NSLog(@"..1");
// 因?yàn)槭遣⑿嘘?duì)列,下面的block不需要等待當(dāng)前block執(zhí)行完畢,就不會(huì)發(fā)生死鎖。
dispatch_sync(queue, ^{
NSLog(@"..2");
});
});
NSLog(@"here");
@end
單例
dispatch_once() 以線程安全的方式執(zhí)行且僅執(zhí)行其代碼塊一次。試圖訪問(wèn)臨界區(qū)(即傳遞給 dispatch_once 的代碼)的不同的線程會(huì)在臨界區(qū)已有一個(gè)線程的情況下被阻塞,直到臨界區(qū)完成為止。
@implementation User
+ (instancetype)sharedUser
{
static User *instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[User alloc] init];
});
return instance;
}
@end
調(diào)度組
Dispatch Group 會(huì)在整個(gè)組的任務(wù)都完成時(shí)通知你。這些任務(wù)可以是同步的,也可以是異步的,即便在不同的隊(duì)列也行。而且在整個(gè)組的任務(wù)都完成時(shí),Dispatch Group 可以用同步的或者異步的方式通知你。
創(chuàng)建group Api | 備注 |
---|---|
dispatch_group_t dispatch_group_create (void) |
創(chuàng)建一個(gè)group |
將任務(wù)(block)添加到group | 備注 |
---|---|
dispatch_group_async (dispatch_group_t group,dispatch_queue_t queue, dispatch_block_t block) |
異步把block提交到queue,并且將block分配到指定的group |
dispatch_group_enter (dispatch_group_t group) |
手動(dòng)表明block進(jìn)入group,dispatch_group_enter 與dispatch_group_leave 是成對(duì)出現(xiàn)的。 |
dispatch_group_leave (dispatch_group_t group) |
手動(dòng)表明block在group中執(zhí)行完成 |
設(shè)置group完成時(shí)的通知/回調(diào) | 備注 |
---|---|
dispatch_group_wait (dispatch_group_t group, dispatch_time_t timeout) |
阻塞當(dāng)前線程,直到group里面所有的任務(wù)都完成或者等到某個(gè)超時(shí)發(fā)生 |
dispatch_group_notify (dispatch_group_t group, dispatch_queue_t queue, dispatch_block_t block) |
異步設(shè)置group里所有任務(wù)都完成時(shí),在queue隊(duì)列中執(zhí)行通知回調(diào)block |
多圖片下載示例:
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
for(NSInteger i = 0; i < 10; i++)
{
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"http://a/%zd.png", i]];
// 表示block進(jìn)入group
dispatch_group_enter(group);
[[SDWebImageDownloader sharedDownloader] downloadImageWithURL:url options:0 progress:nil completed:^(UIImage *image, NSData *data, NSError *error, BOOL finished) {
// 表示block執(zhí)行完成
dispatch_group_leave(group);
}];
}
// 設(shè)置等待3秒鐘
dispatch_time_t timeoutTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC));
if(dispatch_group_wait(group, timeoutTime))
{
NSLog(@"圖片下載超時(shí)");
}
else
{
NSLog(@"所有圖片都下載完成");
}
});
信號(hào)量
信號(hào)量讓你控制多個(gè)消費(fèi)者對(duì)有限數(shù)量資源的訪問(wèn)
原則:當(dāng)信號(hào)量小于等于0時(shí),dispatch_semaphore_wait
會(huì)阻塞線程,當(dāng)dispatch_semaphore_signal
時(shí)會(huì)讓信號(hào)量加1,如果這時(shí)信號(hào)量大于0,則喚醒阻塞的線程。
Api | 備注 |
---|---|
dispatch_semaphore_t dispatch_semaphore_create (long value) |
創(chuàng)建一個(gè)信號(hào)量,并且設(shè)置信號(hào)量的初始值 |
dispatch_semaphore_wait (dispatch_semaphore_t dsema, dispatch_time_t timeout) |
等待一個(gè)信號(hào)量,如果當(dāng)前信號(hào)量大于0,則信號(hào)量減1,線程往下執(zhí)行。否則線程阻塞,直到被信號(hào)量大于0時(shí)被喚醒或者等待超時(shí) |
dispatch_semaphore_signal (dispatch_semaphore_t dsema) |
讓信號(hào)量加1,如果當(dāng)前信號(hào)量大于0,則喚醒一個(gè)waiting的線程 |
圖片下載示例:
// 創(chuàng)建信號(hào)量,并且初始化為0
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
// 下載圖片
[[SDWebImageDownloader sharedDownloader] downloadImageWithURL:[NSURL URLWithString:@"http://a/b.png"] options:0 progress:nil completed:^(UIImage *image, NSData *data, NSError *error, BOOL finished) {
// 設(shè)置信號(hào)量+1,此時(shí)信號(hào)量大于0,會(huì)喚醒等待的線程。
dispatch_semaphore_signal(semaphore);
}];
// 設(shè)置等待3秒鐘
dispatch_time_t timeoutTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 \\* NSEC_PER_SEC));
// 此時(shí)線程會(huì)阻塞,只到圖片下載完成或者等待超時(shí)
if(dispatch_semaphore_wait(semaphore, timeoutTime))
{
NSLog(@"等待超時(shí)");
}
else
{
NSLog(@"圖片下載完畢");
}