GCD队列、同步异步

GCD的队列有两种,一种是串行队列,一种是并发队列。

串行队列:

任务按往队列里的添加先后顺序执行,先进先出(FIFO),前一个任务执行完再开始执行下一个任务。(我们开发中主线程队列就是一个串行队列,所以我们经常在主线程写的一般任务(不考虑多线程),都是顺序执行的)。

注意一个串行队列里只有一个线程。

并发队列:

任务会在这个队列中新开线程,并发同时执行(无序)。

我们GCD使用常伴有dispatch_sync和dispatch_async,这就是同步执行和异步执行。

同步和异步

同步执行:任务都在当前线程中执行,执行过程中会阻塞当前线程。
异步执行:任务会开辟新的线程,并在新的线程中执行,不会阻塞当前线程。

注意

1.同步执行没有开启新线程的能力, 所有的任务都只能在当前线程执行
2.异步执行有开启新线程的能力, 但是, 有开启新线程的能力, 也不一定会利用这种能力, 也就是说, 异步执行是否开启新线程, 需要具体问题具体分析
3.并发队列中的任务会放到不同的线程中去执行.
4.串行队列中的任务只会放到同一线程中去执行.

基本介绍算是完了,队列有2种,执行方式有2种,那么他们互相组合会是什么情况呢?
很显然,它们可以组合成4种情况:

1).串行队列同步执行:任务都在当前线程执行(同步),并且顺序执行(串行)
2).串行队列异步执行:任务都在开辟的新的子线程中执行(异步),并且顺序执行(串行)
3).并发队列同步执行:任务都在当前线程执行(同步),但是是顺序执行的(并没有体现并发的特性)
4).并发队列异步执行:任务在开辟的多个子线程中执行(异步),并且是同时执行的(并发)

验证:

1.串行队列同步执行

代码直接写在viewDidLoad里

dispatch_queue_t queue = dispatch_queue_create("serialQueue", DISPATCH_QUEUE_SERIAL);
    dispatch_sync(queue, ^{
        NSLog(@"task1");
        NSLog(@"task1---%@",[NSThread currentThread]);
    });
    
    dispatch_sync(queue, ^{
        NSLog(@"task2");
        NSLog(@"task2---%@",[NSThread currentThread]);
    });
    
    dispatch_sync(queue, ^{
        NSLog(@"task3");
        NSLog(@"task3---%@",[NSThread currentThread]);
    });
    
    NSLog(@"task4");
    NSLog(@"task4---%@",[NSThread currentThread]);

结果

2018-01-29 11:26:00.511 GCD[72214:3984485] task1
2018-01-29 11:26:00.512 GCD[72214:3984485] task1---<NSThread: 0x6080002610c0>{number = 1, name = main}
2018-01-29 11:26:00.512 GCD[72214:3984485] task2
2018-01-29 11:26:00.512 GCD[72214:3984485] task2---<NSThread: 0x6080002610c0>{number = 1, name = main}
2018-01-29 11:26:00.512 GCD[72214:3984485] task3
2018-01-29 11:26:00.513 GCD[72214:3984485] task3---<NSThread: 0x6080002610c0>{number = 1, name = main}
2018-01-29 11:26:00.513 GCD[72214:3984485] task4
2018-01-29 11:26:00.513 GCD[72214:3984485] task4---<NSThread: 0x6080002610c0>{number = 1, name = main}

分析:任务是在当前线程(当前是主线程)顺序执行的。这也验证了
串行队列同步执行:任务都在当前线程执行(同步),并且顺序执行(串行)

这里需要注意的是代码直接在viewDidLoad里写的,主队列也是一个串行队列,但在主线程中使用主队列同步执行会造成死锁,这里不讨论这个。另外,若在viewDidLoad新开一个子线程,去执行代码,结果是同样可以验证的:

[NSThread detachNewThreadSelector:@selector(threadAction) toTarget:self withObject:nil];
-(void)threadAction{
    dispatch_queue_t queue = dispatch_queue_create("serialQueue", DISPATCH_QUEUE_SERIAL);
    dispatch_sync(queue, ^{
        NSLog(@"task1");
        NSLog(@"task1---%@",[NSThread currentThread]);
    });
    
    dispatch_sync(queue, ^{
        NSLog(@"task2");
        NSLog(@"task2---%@",[NSThread currentThread]);
    });
    
    dispatch_sync(queue, ^{
        NSLog(@"task3");
        NSLog(@"task3---%@",[NSThread currentThread]);
    });
    
    NSLog(@"task4");
    NSLog(@"task4---%@",[NSThread currentThread]);
}·
2018-01-29 11:27:31.056 GCD[72230:3986823] task1
2018-01-29 11:27:31.056 GCD[72230:3986823] task1---<NSThread: 0x600000075f80>{number = 3, name = (null)}
2018-01-29 11:27:31.057 GCD[72230:3986823] task2
2018-01-29 11:27:31.057 GCD[72230:3986823] task2---<NSThread: 0x600000075f80>{number = 3, name = (null)}
2018-01-29 11:27:31.058 GCD[72230:3986823] task3
2018-01-29 11:27:31.059 GCD[72230:3986823] task3---<NSThread: 0x600000075f80>{number = 3, name = (null)}
2018-01-29 11:27:31.059 GCD[72230:3986823] task4
2018-01-29 11:27:31.059 GCD[72230:3986823] task4---<NSThread: 0x600000075f80>{number = 3, name = (null)}
2.串行队列异步执行
dispatch_queue_t queue = dispatch_queue_create("serialQueue", DISPATCH_QUEUE_SERIAL);
    dispatch_async(queue, ^{
        NSLog(@"task1");
        NSLog(@"task1---%@",[NSThread currentThread]);
    });
    
    dispatch_async(queue, ^{
        NSLog(@"task2");
        NSLog(@"task2---%@",[NSThread currentThread]);
    });
    
    dispatch_async(queue, ^{
        NSLog(@"task3");
        NSLog(@"task3---%@",[NSThread currentThread]);
    });
    
    NSLog(@"task4");
    NSLog(@"task4---%@",[NSThread currentThread]);
2018-01-29 11:30:19.254 GCD[72269:3990336] task1
2018-01-29 11:30:19.254 GCD[72269:3990288] task4
2018-01-29 11:30:19.254 GCD[72269:3990288] task4---<NSThread: 0x60800006df00>{number = 1, name = main}
2018-01-29 11:30:19.254 GCD[72269:3990336] task1---<NSThread: 0x60000007a9c0>{number = 3, name = (null)}
2018-01-29 11:30:19.255 GCD[72269:3990336] task2
2018-01-29 11:30:19.255 GCD[72269:3990336] task2---<NSThread: 0x60000007a9c0>{number = 3, name = (null)}
2018-01-29 11:30:19.255 GCD[72269:3990336] task3
2018-01-29 11:30:19.255 GCD[72269:3990336] task3---<NSThread: 0x60000007a9c0>{number = 3, name = (null)}
2018-01-29 11:32:01.533 GCD[72278:3992351] task4
2018-01-29 11:32:01.533 GCD[72278:3992391] task1
2018-01-29 11:32:01.534 GCD[72278:3992351] task4---<NSThread: 0x60800006d580>{number = 1, name = main}
2018-01-29 11:32:01.534 GCD[72278:3992391] task1---<NSThread: 0x6080000771c0>{number = 3, name = (null)}
2018-01-29 11:32:01.534 GCD[72278:3992391] task2
2018-01-29 11:32:01.534 GCD[72278:3992391] task2---<NSThread: 0x6080000771c0>{number = 3, name = (null)}
2018-01-29 11:32:01.534 GCD[72278:3992391] task3
2018-01-29 11:32:01.535 GCD[72278:3992391] task3---<NSThread: 0x6080000771c0>{number = 3, name = (null)}

分析:主线程异步调用,我们先分析加到队列里的task任务1、2、3,确实都是在开辟了的新线程<NSThread: 0x60000007a9c0>{number = 3, name = (null)}上顺序执行的,关于task4,由于是异步的,它也没加入队列queue,啥时候输出就看电脑心情了...验证结果:
串行队列异步执行:任务都在开辟的新的子线程中执行(异步),并且顺序执行(串行)

这里需要注意,由于新创建了串行线程,所以任务会在新开辟的线程上执行,若是直接在主队列异步调用,任务执行都在主线程上。

3.并发队列同步执行
dispatch_queue_t queue = dispatch_queue_create("concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
    dispatch_sync(queue, ^{
        NSLog(@"task1");
        NSLog(@"task1---%@",[NSThread currentThread]);
    });
    
    dispatch_sync(queue, ^{
        NSLog(@"task2");
        NSLog(@"task2---%@",[NSThread currentThread]);
    });
    
    dispatch_sync(queue, ^{
        NSLog(@"task3");
        NSLog(@"task3---%@",[NSThread currentThread]);
    });
    
    NSLog(@"task4");
    NSLog(@"task4---%@",[NSThread currentThread]);
2018-01-29 11:40:40.274 GCD[72316:3998532] task1
2018-01-29 11:40:40.274 GCD[72316:3998532] task1---<NSThread: 0x60800006ce80>{number = 1, name = main}
2018-01-29 11:40:40.274 GCD[72316:3998532] task2
2018-01-29 11:40:40.274 GCD[72316:3998532] task2---<NSThread: 0x60800006ce80>{number = 1, name = main}
2018-01-29 11:40:40.274 GCD[72316:3998532] task3
2018-01-29 11:40:40.275 GCD[72316:3998532] task3---<NSThread: 0x60800006ce80>{number = 1, name = main}
2018-01-29 11:40:40.275 GCD[72316:3998532] task4
2018-01-29 11:40:40.275 GCD[72316:3998532] task4---<NSThread: 0x60800006ce80>{number = 1, name = main}

分析:任务是在当前线程(是主线程没有开辟新线程)顺序执行的,跟串行同步一样,虽是并发队列,却不能并发。得到验证结果:
并发队列同步执行:任务都在当前线程执行(同步),但是是顺序执行的(并没有体现并发的特性)

4.并发队列异步执行
dispatch_queue_t queue = dispatch_queue_create("concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(queue, ^{
        NSLog(@"task1");
        NSLog(@"task1---%@",[NSThread currentThread]);
    });
    
    dispatch_async(queue, ^{
        NSLog(@"task2");
        NSLog(@"task2---%@",[NSThread currentThread]);
    });
    
    dispatch_async(queue, ^{
        NSLog(@"task3");
        NSLog(@"task3---%@",[NSThread currentThread]);
    });
    
    NSLog(@"task4");
    NSLog(@"task4---%@",[NSThread currentThread]);
2018-01-29 11:47:23.235 GCD[72367:4005184] task2
2018-01-29 11:47:23.235 GCD[72367:4005156] task4
2018-01-29 11:47:23.235 GCD[72367:4005183] task1
2018-01-29 11:47:23.235 GCD[72367:4005186] task3
2018-01-29 11:47:23.236 GCD[72367:4005156] task4---<NSThread: 0x600000262a80>{number = 1, name = main}
2018-01-29 11:47:23.236 GCD[72367:4005184] task2---<NSThread: 0x608000267500>{number = 3, name = (null)}
2018-01-29 11:47:23.236 GCD[72367:4005183] task1---<NSThread: 0x60000026f380>{number = 4, name = (null)}
2018-01-29 11:47:23.236 GCD[72367:4005186] task3---<NSThread: 0x608000267540>{number = 5, name = (null)}
2018-01-29 11:48:23.070 GCD[72375:4006982] task1
2018-01-29 11:48:23.070 GCD[72375:4006934] task4
2018-01-29 11:48:23.070 GCD[72375:4006984] task3
2018-01-29 11:48:23.070 GCD[72375:4006981] task2
2018-01-29 11:48:23.070 GCD[72375:4006934] task4---<NSThread: 0x608000068300>{number = 1, name = main}
2018-01-29 11:48:23.070 GCD[72375:4006982] task1---<NSThread: 0x60000006db40>{number = 3, name = (null)}
2018-01-29 11:48:23.071 GCD[72375:4006984] task3---<NSThread: 0x608000074300>{number = 4, name = (null)}
2018-01-29 11:48:23.071 GCD[72375:4006981] task2---<NSThread: 0x60000006d140>{number = 5, name = (null)}
2018-01-29 11:48:42.930 GCD[72380:4007604] task4
2018-01-29 11:48:42.930 GCD[72380:4007680] task2
2018-01-29 11:48:42.930 GCD[72380:4007683] task1
2018-01-29 11:48:42.930 GCD[72380:4007681] task3
2018-01-29 11:48:42.930 GCD[72380:4007604] task4---<NSThread: 0x6000000742c0>{number = 1, name = main}
2018-01-29 11:48:42.930 GCD[72380:4007680] task2---<NSThread: 0x60800007d680>{number = 3, name = (null)}
2018-01-29 11:48:42.930 GCD[72380:4007683] task1---<NSThread: 0x60000007f500>{number = 4, name = (null)}
2018-01-29 11:48:42.930 GCD[72380:4007681] task3---<NSThread: 0x60800007d5c0>{number = 5, name = (null)}

分析:先看task4吧,没有加入队列,所以肯定是在主线程执行的,由于异步,啥时候执行还是要看电脑心情...好了,言归正传,我们看加入到并发队列里的任务1、2、3,三个运行结果证明它们是在不同的线程中无序执行的,每个任务都开辟了新的线程去执行,并且执行顺序是无序的,体现了并发的特性。所以我们经常也是使用这种方式做一些需求。验证结果:
并发队列异步执行:任务在开辟的多个子线程中执行(异步),并且是同时执行的(并发)

最后总结一下:理解了串行并发和同步异步,我们的开发会变得更加高效,逻辑也会更加清晰,若你暂时没没弄懂,可以再回上去看看理论,跟着理论敲敲代码来加深理解

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容