1,對于創(chuàng)建全局使用的串行或者并行隊列,都應(yīng)該用strong修飾,例如
- @property (nonatomic,strong) dispatch_queue_t dispatch_serial
這是因為在ios6.0之前,oc是沒辦法自動管理gcd隊列的,所以在iOS6.0之前要使用assign。但是iOS6.0之后,蘋果在oc里面加入了自動管理gcd的功能。
2,有關(guān)內(nèi)容的學習
這里首先要記住
串行隊列是:DISPATCH_QUEUE_SERIAL
并行隊列是:DISPATCH_QUEUE_CONCURRENT
同步執(zhí)行:dispatch_sync(<這里寫是串行還是并行>, {<代碼要完成的事>})
異步執(zhí)行:dispatch_async(<這里寫是串行還是并行>, {<代碼要完成的事>})
注:只要是異步執(zhí)行都會創(chuàng)建新的線程,同步執(zhí)行不會創(chuàng)建新的線程。串行隊列肯定是上一個任務(wù)執(zhí)行完才會執(zhí)行下一個任務(wù),并行隊列理論上可以說是同時執(zhí)行,任務(wù)完成的順序和cpu的分配有關(guān)
首選聲明兩個全局使用的隊列,一個串行隊列,一個并行隊列
@property (nonatomic,strong) dispatch_queue_t dispatch_serial;/**<串行隊列*/
@property (nonatomic,strong) dispatch_queue_t dispatch_concurrent;/**<并行隊列*/
在viewDidLoad里面創(chuàng)建這兩個隊列
- (void)viewDidLoad {
[super viewDidLoad];
//創(chuàng)建兩個隊列
_dispatch_serial = dispatch_queue_create("dispatch_serial", DISPATCH_QUEUE_SERIAL);
_dispatch_concurrent = dispatch_queue_create("dispatch_concurrent", DISPATCH_QUEUE_CONCURRENT);
[self serialAndSynchronize];
[self serialAndASynchronize];
[self concurrentAndSynchronize];
[self concurrentAndASynchronize];
}
下面就是對不同情況下簡單的使用
串行同步隊列
//串行同步隊列
-(void)serialAndSynchronize{
dispatch_sync(_dispatch_serial, ^{
NSLog(@"1---------%@",[NSThread currentThread]);
});
dispatch_sync(_dispatch_serial, ^{
NSLog(@"2---------- %@",[NSThread currentThread]);
});
dispatch_sync(_dispatch_serial, ^{
NSLog(@"3---------- %@",[NSThread currentThread]);
});
NSLog(@"4------------ %@",[NSThread currentThread]);
}
打印的數(shù)據(jù)
2017-08-31 14:23:52.340 SYGCDStudy[8903:207494] 1---------<NSThread: 0x60000006c700>{number = 1, name = main}
2017-08-31 14:23:52.340 SYGCDStudy[8903:207494] 2---------- <NSThread: 0x60000006c700>{number = 1, name = main}
2017-08-31 14:23:52.340 SYGCDStudy[8903:207494] 3---------- <NSThread: 0x60000006c700>{number = 1, name = main}
2017-08-31 14:23:52.341 SYGCDStudy[8903:207494] 4------------ <NSThread: 0x60000006c700>{number = 1, name = main}
這里可以看到。串行同步隊列實際上都是在主線程上面執(zhí)行的,而且沒有創(chuàng)建新的線程,并行都是按照順序執(zhí)行的,必須等前一個執(zhí)行結(jié)束,才會執(zhí)行下一個
串行異步隊列
//串行異步隊列
-(void)serialAndASynchronize{
dispatch_async(_dispatch_serial, ^{
NSLog(@"1------------ %@",[NSThread currentThread]);
});
dispatch_async(_dispatch_serial, ^{
NSLog(@"2------------ %@",[NSThread currentThread]);
});
dispatch_async(_dispatch_serial, ^{
NSLog(@"3------------ %@",[NSThread currentThread]);
});
NSLog(@"4------------ %@",[NSThread currentThread]);
}
打印的數(shù)據(jù)
2017-08-31 14:25:02.175 SYGCDStudy[8925:209538] 1------------ <NSThread: 0x600000267000>{number = 3, name = (null)}
2017-08-31 14:25:02.175 SYGCDStudy[8925:209484] 4------------ <NSThread: 0x60800007ca80>{number = 1, name = main}
2017-08-31 14:25:02.175 SYGCDStudy[8925:209538] 2------------ <NSThread: 0x600000267000>{number = 3, name = (null)}
2017-08-31 14:25:02.175 SYGCDStudy[8925:209538] 3------------ <NSThread: 0x600000267000>{number = 3, name = (null)}
先打印了4,然后順序在子線程中打印1,2,3。說明異步執(zhí)行具有開辟新線程的能力,并且串行隊列必須等到前一個任務(wù)執(zhí)行完才能開始執(zhí)行下一個任務(wù),同時,異步執(zhí)行會使內(nèi)部函數(shù)率先返回,不會與正在執(zhí)行的外部函數(shù)發(fā)生死鎖。
并行同步隊列
//并行同步隊列
-(void)concurrentAndSynchronize{
dispatch_sync(_dispatch_concurrent, ^{
NSLog(@"1------------ %@",[NSThread currentThread]);
});
dispatch_sync(_dispatch_concurrent, ^{
NSLog(@"2------------ %@",[NSThread currentThread]);
});
dispatch_sync(_dispatch_concurrent, ^{
NSLog(@"3------------ %@",[NSThread currentThread]);
});
NSLog(@"4------------ %@",[NSThread currentThread]);
}
打印的數(shù)據(jù)
2017-08-31 14:30:10.572 SYGCDStudy[8953:213767] 1------------ <NSThread: 0x60800007c180>{number = 1, name = main}
2017-08-31 14:30:10.572 SYGCDStudy[8953:213767] 2------------ <NSThread: 0x60800007c180>{number = 1, name = main}
2017-08-31 14:30:10.573 SYGCDStudy[8953:213767] 3------------ <NSThread: 0x60800007c180>{number = 1, name = main}
2017-08-31 14:30:10.573 SYGCDStudy[8953:213767] 4------------ <NSThread: 0x60800007c180>{number = 1, name = main}
未開啟新的線程執(zhí)行任務(wù),并且Block函數(shù)執(zhí)行完成后dispatch函數(shù)才會返回,才能繼續(xù)向下執(zhí)行,所以我們看到的結(jié)果是順序打印的。
并行異步隊列
//并行異步隊列
-(void)concurrentAndASynchronize{
dispatch_async(_dispatch_concurrent, ^{
NSLog(@"1------------ %@",[NSThread currentThread]);
});
dispatch_async(_dispatch_concurrent, ^{
NSLog(@"2------------ %@",[NSThread currentThread]);
});
dispatch_async(_dispatch_concurrent, ^{
NSLog(@"3------------ %@",[NSThread currentThread]);
});
NSLog(@"4------------ %@",[NSThread currentThread]);
}
打印的數(shù)據(jù)
2017-08-31 14:34:08.966 SYGCDStudy[9008:220555] 3------------ <NSThread: 0x608000079380>{number = 5, name = (null)}
2017-08-31 14:34:08.966 SYGCDStudy[9008:220478] 4------------ <NSThread: 0x60000006da80>{number = 1, name = main}
2017-08-31 14:34:08.966 SYGCDStudy[9008:220557] 2------------ <NSThread: 0x600000077340>{number = 4, name = (null)}
2017-08-31 14:34:08.966 SYGCDStudy[9008:220554] 1------------ <NSThread: 0x608000079040>{number = 3, name = (null)}
開辟了多個線程,觸發(fā)任務(wù)的時機是順序的,但是我們看到完成任務(wù)的時間卻是隨機的,這取決于CPU對于不同線程的調(diào)度分配,但是,線程不是無條件無限開辟的,當任務(wù)量足夠大時,線程是會重復(fù)利用的。
3,其他一些常用的gcd方法
dispatch_once ,只執(zhí)行一次的方法
//只執(zhí)行一次
- (IBAction)carryOutOne:(id)sender {
static dispatch_once_t oneDispatch;
dispatch_once(&oneDispatch, ^{
NSLog(@"這個方法只會執(zhí)行一次");
});
}
無論調(diào)起幾次這個方法,打印只會進行一次
dispatch_apply ,重復(fù)執(zhí)行, 如果任務(wù)隊列是并行隊列,重復(fù)執(zhí)行的任務(wù)會并發(fā)執(zhí)行,如果任務(wù)隊列為串行隊列,則任務(wù)會順序執(zhí)行,需要注意的是,該函數(shù)為同步函數(shù),要防止線程阻塞和死鎖
//重復(fù)執(zhí)行
- (IBAction)recurButton:(id)sender {
dispatch_apply(5, _dispatch_serial, ^(size_t i) {
NSLog(@"重復(fù)執(zhí)行的次數(shù)。 %ld",i);
});
}
dispatch_after,延時執(zhí)行,其中參數(shù)dispatch_time_t代表延時時長,dispatch_queue_t代表使用哪個隊列。如果隊列是主隊列,那么任務(wù)在主線程執(zhí)行,如果隊列為全局隊列或者自己創(chuàng)建的隊列,那么任務(wù)在子線程執(zhí)行
//延時執(zhí)行
- (IBAction)afterButton:(id)sender {
NSLog(@"延時三秒執(zhí)行主線程--- 開始時間。%@",[NSDate date]);
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC));
dispatch_after(time, dispatch_get_main_queue(), ^{
NSLog(@"延時三秒執(zhí)行主線程。%@",[NSDate date]);
});
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"延時五秒執(zhí)行主線程。%@",[NSDate date]);
});
}
dispatch_group_async ,組隊列 。dispatch_group_notify,接收組隊列完成后執(zhí)行的隊列。當加入到隊列組中的所有任務(wù)執(zhí)行完成之后,會調(diào)用dispatch_group_notify函數(shù)通知任務(wù)全部完成
//分組完成
- (IBAction)groupButton:(id)sender {
dispatch_group_t groupDispatch = dispatch_group_create();
__block NSInteger index_1 = 0;
__block NSInteger index_2 = 0;
dispatch_group_async(groupDispatch, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
dispatch_apply(10000, _dispatch_serial, ^(size_t i) {
index_1 = index_1 + i;
});
});
dispatch_group_async(groupDispatch, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
dispatch_apply(2000, _dispatch_serial, ^(size_t i) {
index_2 = index_2 + i;
});
});
dispatch_group_notify(groupDispatch, dispatch_get_main_queue(), ^{
NSLog(@"這時候的 %ld,%ld",index_1,index_2);
});
}
該文章練習的demo地址:demo