GCD Group、Barrier、Semaphore、NSOperationQueue使用

先贴上打印函数:

- (void)p_printThread:(int)index {
    NSLog(@"%@-------%d", [NSThread currentThread], index);
}

1. Group

Group作用:在并发异步队列中,等待执行一系列任务后,再执行一个任务。实现方式有两种:notify和wait。
notify示例代码:

dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_group_t group = dispatch_group_create();
    dispatch_group_async(group, concurrentQueue, ^{ 
        [self p_printThread:1];
    });
    dispatch_group_async(group, concurrentQueue, ^{ 
        [self p_printThread:2];
    });
    dispatch_group_async(group, concurrentQueue, ^{
        [self p_printThread:3];
    });
    dispatch_group_async(group, concurrentQueue, ^{ 
        [self p_printThread:4];
    });
    // 使用dispatch_group_wait,可以阻塞线程,等待group的任务执行完毕,才能继续执行后续任务
    // 使用dispatch_group_notify,不会阻塞线程(group外的线程执行顺序不受影响),而且可以在执行完成group的任务后进行操作
    dispatch_group_notify(group, concurrentQueue, ^{
        [self p_printThread:0];
    });

打印结果:

<NSThread: 0x610000260d80>{number = 4, name = (null)}-------2
<NSThread: 0x608000261400>{number = 5, name = (null)}-------3
<NSThread: 0x618000264f40>{number = 3, name = (null)}-------1
<NSThread: 0x610000260e40>{number = 6, name = (null)}-------4
<NSThread: 0x610000260e40>{number = 6, name = (null)}-------0

wait示例代码:

dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_group_t group = dispatch_group_create();
    for (int i=0; i<4; i++)  {
        dispatch_group_enter(group);
        dispatch_async(concurrentQueue, ^{
            [self p_printThread:i+1];
        });   
        dispatch_group_leave(group);
    }
    // 使用dispatch_group_wait,可以阻塞线程,等待group的任务执行完毕
    dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
    dispatch_async(dispatch_get_main_queue(), ^{
        // 主线程处理
        [self p_printThread:0];
    });

打印结果:

<NSThread: 0x600000076600>{number = 4, name = (null)}-------2
<NSThread: 0x600000076740>{number = 6, name = (null)}-------4
<NSThread: 0x610000073280>{number = 3, name = (null)}-------1
<NSThread: 0x608000076380>{number = 5, name = (null)}-------3
<NSThread: 0x60000007b240>{number = 1, name = main}-------0

结论:运行多次,任务1、2、3、4的顺序不定,但任务0总是最后一个。应用场景:单界面多请求完成后,主线程刷新界面;notify和wait的区别:wait会阻塞线程,notify不会阻塞线程,较好一点

2. Barrier

Barrier作用:Barrier在并发异步队列中起到承上启下的作用(Barrier就像名字一样,类似一个栅栏把前后的任务隔开了)。Barrier前后任务执行顺序为:Barrier前面的线程(多个的话,仍是并行)--->barrier线程--->barrier后面的线程(多个的话,仍是并行)。需要注意的是:Barrier在全局并发队列不起作用,只有在自己创建的并发队列才起作用。

示例代码:

// barrier在dispatch_get_global_queue创建的并行队列中不起作用,需要使用dispatch_queue_create来创建的并行队列才可以
    //dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_queue_t concurrentQueue = dispatch_queue_create("com.concurrent.queue", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(concurrentQueue, ^(){
        [self p_printThread:1];
    });
    dispatch_async(concurrentQueue, ^(){
        [self p_printThread:2];
    });
    dispatch_async(concurrentQueue, ^(){
        [self p_printThread:3];
    });
    dispatch_barrier_async(concurrentQueue, ^(){
        [self p_printThread:0];
    });
    dispatch_async(concurrentQueue, ^(){
        [self p_printThread:4];
    });
    dispatch_async(concurrentQueue, ^(){
        [self p_printThread:5];
    });
    dispatch_async(concurrentQueue, ^(){
        [self p_printThread:6];
    });

打印结果:

<NSThread: 0x600000079300>{number = 4, name = (null)}-------2
<NSThread: 0x6000000790c0>{number = 5, name = (null)}-------3
<NSThread: 0x610000076100>{number = 3, name = (null)}-------1
<NSThread: 0x610000076100>{number = 3, name = (null)}-------0
<NSThread: 0x610000076100>{number = 3, name = (null)}-------4
<NSThread: 0x600000079300>{number = 4, name = (null)}-------6
<NSThread: 0x600000078d40>{number = 6, name = (null)}-------5

结论:运行多次后可以看出,Barrier的任务0总是在任务1、2、3之后,而且总是在任务4、5、6之前,但是任务1、2、3的执行顺序不定,任务4、5、6的执行顺序也不定。Barrier的任务就像“栅栏”一样隔开了前后的任务。

3. Semaphore

Semaphore作用:信号量可以用来控制同时访问资源的线程数量:比如系统只有两个资源可以用,有三个线程要访问,那么只能允许两个线程同时访问,第三个线程应当等待资源被释放后再访问。使用信号量可以实现类似于NSOperationQueue里的并发控制:信号数>0,执行任务;信号数<=0,阻塞线程
示例代码:

// 下面的例子只允许3个线程同时执行
dispatch_semaphore_t semaphore = dispatch_semaphore_create(3);// 创建一个信号量,初始值为3
    dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    for (int i=0; i<10; i++) {
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);// 计数-1
        dispatch_async(concurrentQueue, ^{
            [self p_printThread:i];
            sleep(5);
            dispatch_semaphore_signal(semaphore);// 计数+1
        });
    }

打印结果:
<NSThread: 0x608000077b80>{number = 5, name = (null)}-------2
<NSThread: 0x610000074fc0>{number = 3, name = (null)}-------0
<NSThread: 0x6000000787c0>{number = 4, name = (null)}-------1

<NSThread: 0x6000000787c0>{number = 4, name = (null)}-------3
<NSThread: 0x610000074fc0>{number = 3, name = (null)}-------4
<NSThread: 0x608000077b80>{number = 5, name = (null)}-------5

<NSThread: 0x6000000787c0>{number = 4, name = (null)}-------7
<NSThread: 0x608000077b80>{number = 5, name = (null)}-------6
<NSThread: 0x610000074fc0>{number = 3, name = (null)}-------8

<NSThread: 0x610000074fc0>{number = 3, name = (null)}-------9
结论:由于信号量的值为3,每次只能同时执行3个线程里的任务

4. NSOperationQueue

NSOperationQueue作用:
1.将NSOperation添加到NSOperationQueue,使其异步执行 === GCD并行异步队列。2.NSOperationQueue可以设置依赖关系 ~= GCD Group notify / GCD Group Wait / GCD Barrier。
3.可以设置最大并发数量(同时执行的线程数) === GCD 信号量
示例代码:

NSOperationQueue *operationQueue = [NSOperationQueue new];
    NSBlockOperation *blockOperation1 = [NSBlockOperation blockOperationWithBlock:^{
        [self p_printThread:1];
        sleep(5);
    }];
    NSBlockOperation *blockOperation2 = [NSBlockOperation blockOperationWithBlock:^{
        [self p_printThread:2];
        sleep(5);
    }];
    NSBlockOperation *blockOperation3 = [NSBlockOperation blockOperationWithBlock:^{
        [self p_printThread:3];
        sleep(5);
    }];
    NSBlockOperation *blockOperation4 = [NSBlockOperation blockOperationWithBlock:^{
        [self p_printThread:4];
        sleep(5);
    }];
    
    // 2.NSOperationQueue可以设置依赖关系 ~=  GCD Group notify / GCD Group Wait / GCD Barrier
    [blockOperation1 addDependency:blockOperation2];
  
    // 3.可以设置最大并发数量(同时执行的线程数) === GCD 信号量
    operationQueue.maxConcurrentOperationCount = 1;

    [operationQueue addOperations:@[blockOperation1, blockOperation2, blockOperation3, blockOperation4] waitUntilFinished:YES];

打印结果:

<NSThread: 0x600000078300>{number = 3, name = (null)}-------2

<NSThread: 0x600000078300>{number = 3, name = (null)}-------1

<NSThread: 0x60000007aa80>{number = 4, name = (null)}-------3

<NSThread: 0x60000007aa80>{number = 4, name = (null)}-------4

结论:运行多次可以看出,每次只能执行一个线程里的任务(这个类似信号量的控制);虽然任务1、2、3、4的顺序不定,但是任务1总是在任务2的后面(类似group的notify和wait)。对比可以看出NSOperationQueue使用更方便一些,语法也更接近Objective-C。

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

推荐阅读更多精彩内容