GCD的相关使用

一、同步执行 + 主队列

/**
 * 同步执行 + 主队列
 * 特点(主线程调用):互等卡主不执行。
 * 特点(其他线程调用):不会开启新线程,执行完一个任务,再执行下一个任务。
 */
- (void)syncMain {
    NSLog(@"currentThread---%@",[NSThread currentThread]);  // 打印当前线程
    NSLog(@"开启");
    
    dispatch_queue_t queue = dispatch_get_main_queue();
    dispatch_sync(queue, ^{
        NSLog(@"1---%@",[NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"2---%@",[NSThread currentThread]);
    });
    
    NSLog(@"结束");
}

运行结果:

currentThread---<NSThread: 0x600001904240>{number = 1, name = main}
开启

线程死锁。为什么呢?
- (void)syncMain {} ----> 任务AGCD同步任务 ----> 任务B
      任务A在主队列,并且已经开始执行(打印出currentThread),这个时候任务B被加入到主队列中,并且同步执行,且不能开新的线程。
      任务B得等Block函数执行完成,才能返回,然而主队列是串行的,得等任务A执行完才能去执行任务B的Block。
      造成了任务A在等任务B完成才能继续执行,但是串行队列中,又不能让任务B在任务A未完成之前开始执行,相互等待,造成了死锁。

二、同步执行 + 并发队列

/**
 * 同步执行 + 并发队列
 * 特点:在当前线程中执行任务,不会开启新线程,执行完一个任务,再执行下一个任务。
 */
- (void)syncConcurrent {
    NSLog(@"currentThread---%@",[NSThread currentThread]);  // 打印当前线程
    NSLog(@"开启");
    
    dispatch_queue_t queue = dispatch_queue_create("syncConcurrent", DISPATCH_QUEUE_CONCURRENT);
    dispatch_sync(queue, ^{
        NSLog(@"1---%@",[NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"2---%@",[NSThread currentThread]);
    });
    
    NSLog(@"结束");
}

运行结果:

currentThread---<NSThread: 0x600003e0c1c0>{number = 1, name = main}
开启
1---<NSThread: 0x600003e0c1c0>{number = 1, name = main}
2---<NSThread: 0x600003e0c1c0>{number = 1, name = main}
结束

三、异步执行 + 并发队列

/**
 * 异步执行 + 并发队列
 * 特点:可以开启多个线程,任务交替(同时)执行。
 */
- (void)asyncConcurrent {
    NSLog(@"currentThread---%@",[NSThread currentThread]);  // 打印当前线程
    NSLog(@"开启");
    
    dispatch_queue_t queue = dispatch_queue_create("asyncConcurrent", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(queue, ^{
        NSLog(@"1---%@",[NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"2---%@",[NSThread currentThread]);
    });
    
    NSLog(@"结束");
}

运行结果:

currentThread---<NSThread: 0x600000d48980>{number = 1, name = main}
开启
结束
1---<NSThread: 0x600000d019c0>{number = 5, name = (null)}
2---<NSThread: 0x600000d00500>{number = 6, name = (null)}

四、同步执行 + 串行队列

/**
 * 同步执行 + 串行队列
 * 特点:不会开启新线程,在当前线程执行任务。任务是串行的,执行完一个任务,再执行下一个任务。
 */
- (void)syncSerial {
    NSLog(@"currentThread---%@",[NSThread currentThread]);  // 打印当前线程
    NSLog(@"开启");
    
    dispatch_queue_t queue = dispatch_queue_create("syncSerial", DISPATCH_QUEUE_SERIAL);
    dispatch_sync(queue, ^{
        NSLog(@"1---%@",[NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"2---%@",[NSThread currentThread]);
    });
    
    NSLog(@"结束");
}

运行结果:

currentThread---<NSThread: 0x600001284240>{number = 1, name = main}
开启
1---<NSThread: 0x600001284240>{number = 1, name = main}
2---<NSThread: 0x600001284240>{number = 1, name = main}
结束

五、异步执行 + 串行队列

/**
 * 异步执行 + 串行队列
 * 特点:会开启新线程,但是因为任务是串行的,执行完一个任务,再执行下一个任务。
 */
- (void)asyncSerial {
    NSLog(@"currentThread---%@",[NSThread currentThread]);  // 打印当前线程
    NSLog(@"开启");
    
    dispatch_queue_t queue = dispatch_queue_create("asyncConcurrent", DISPATCH_QUEUE_SERIAL);
    dispatch_async(queue, ^{
        NSLog(@"1---%@",[NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"2---%@",[NSThread currentThread]);
    });
    
    NSLog(@"结束");
}

运行结果:

currentThread---<NSThread: 0x6000025ac580>{number = 1, name = main}
开启
结束
1---<NSThread: 0x6000025fc680>{number = 4, name = (null)}
2---<NSThread: 0x6000025fc680>{number = 4, name = (null)}

六、其他函数用法

1、dispatch_after

- (void)GCDDelay {
    NSLog(@"current_%@",[NSThread currentThread]);
    //主队列延时
    dispatch_time_t when_main = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC));
    dispatch_after(when_main, dispatch_get_main_queue(), ^{
        NSLog(@"main_%@",[NSThread currentThread]);
    });
    
    //全局队列延时
    dispatch_time_t when_global = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC));
    dispatch_after(when_global, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSLog(@"global_%@",[NSThread currentThread]);
    });
    
    //自定义队列延时
    dispatch_queue_t customeQue = dispatch_queue_create("customeQue", DISPATCH_QUEUE_SERIAL);
    dispatch_time_t when_global_custom = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC));
    dispatch_after(when_global_custom, customeQue, ^{
        NSLog(@"when_global_custom_%@",[NSThread currentThread]);
    });
}
current_<NSThread: 0x600003fe8980>{number = 1, name = main}
main_<NSThread: 0x600003fe8980>{number = 1, name = main}
when_global_custom_<NSThread: 0x600003fa58c0>{number = 7, name = (null)}
global_<NSThread: 0x600003fad280>{number = 5, name = (null)}

      我们可以看到,当队列是主队列时,任务是在主线程执行;当队列为全局或自定义时,任务是在子线程中执行

2、dispatch_once

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{

    NSLog(@"current_%@",[NSThread currentThread]);
    
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        NSLog(@"%@",[NSThread currentThread]);
    });
}
current_<NSThread: 0x600001cf8900>{number = 1, name = main}
<NSThread: 0x600001cf8900>{number = 1, name = main}

      程序运行期间,只会执行一次打印,任务在主线程中执行

3、dispatch_group_async & dispatch_group_notify

- (void)GCDGroup {
    
    NSLog(@"start_%@",[NSThread currentThread]);
    
    dispatch_group_t group = dispatch_group_create();
    dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSLog(@"1---%@",[NSThread currentThread]);
    });
    dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSLog(@"2---%@",[NSThread currentThread]);
    });
    dispatch_group_notify(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSLog(@"3---%@",[NSThread currentThread]);
    });
    NSLog(@"end_%@",[NSThread currentThread]);
}
start_<NSThread: 0x6000032a0980>{number = 1, name = main}
end_<NSThread: 0x6000032a0980>{number = 1, name = main}
1---<NSThread: 0x6000032a8880>{number = 6, name = (null)}
2---<NSThread: 0x6000032ed4c0>{number = 3, name = (null)}
3---<NSThread: 0x6000032ed4c0>{number = 3, name = (null)}

dispatch_group_asyncdispatch_get_global_queue时会开辟新的线程执行任务,任务会在子线程中执行
dispatch_group_notify只会在dispatch_group_async都执行完后才会执行

4、dispatch_barrier_async

- (void)GCDBarrier {
    
    NSLog(@"start_%@",[NSThread currentThread]);
    dispatch_queue_t myQueue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_SERIAL);
    
    dispatch_async(myQueue, ^{
        NSLog(@"1---%@",[NSThread currentThread]);
    });
    dispatch_async(myQueue, ^{
        NSLog(@"2---%@",[NSThread currentThread]);
    });
    //同步sync
    dispatch_barrier_sync(myQueue, ^{
        NSLog(@"barrier---%@",[NSThread currentThread]);
    });
    dispatch_async(myQueue, ^{
        NSLog(@"3---%@",[NSThread currentThread]);
    });
    dispatch_async(myQueue, ^{
        NSLog(@"4---%@",[NSThread currentThread]);
    });
    
    NSLog(@"end_%@",[NSThread currentThread]);
}
myQueue为自定义时:
start_<NSThread: 0x600001044980>{number = 1, name = main}
2---<NSThread: 0x600001008a80>{number = 6, name = (null)}
1---<NSThread: 0x60000104db80>{number = 5, name = (null)}
barrier---<NSThread: 0x600001044980>{number = 1, name = main}
end_<NSThread: 0x600001044980>{number = 1, name = main}
3---<NSThread: 0x60000104db80>{number = 5, name = (null)}
4---<NSThread: 0x600001008a80>{number = 6, name = (null)}

myQueue为:dispatch_get_global_queue(0,0)时
start_<NSThread: 0x600001f90a00>{number = 1, name = main}
barrier---<NSThread: 0x600001f90a00>{number = 1, name = main}
1---<NSThread: 0x600001fdacc0>{number = 6, name = (null)}
2---<NSThread: 0x600001fd5340>{number = 7, name = (null)}
3---<NSThread: 0x600001fdacc0>{number = 6, name = (null)}
end_<NSThread: 0x600001f90a00>{number = 1, name = main}
4---<NSThread: 0x600001fc5080>{number = 4, name = (null)}
  • 当队列为自定义时,使用dispatch_barrier_sync ()后,任务3、4必须等任务1、2执行完后才能执行
  • 当队列是dispatch_get_global_queue(0,0)时,就算使用了dispatch_barrier_sync (),执行顺序随机不固定
  • 当队列是dispatch_get_main_queue()时,死锁

5、dispatch_apply

- (void)GCDApply {
    dispatch_queue_t myQueue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_SERIAL);
    //重复执行
    dispatch_apply(5, myQueue, ^(size_t i) {
        NSLog(@"第%@次_%@",@(i),[NSThread currentThread]);
    });
}
myQueue为串行:
start_<NSThread: 0x600003d70980>{number = 1, name = main}
第0次_<NSThread: 0x600003d70980>{number = 1, name = main}
第1次_<NSThread: 0x600003d70980>{number = 1, name = main}
第2次_<NSThread: 0x600003d70980>{number = 1, name = main}
第3次_<NSThread: 0x600003d70980>{number = 1, name = main}
第4次_<NSThread: 0x600003d70980>{number = 1, name = main}
end_<NSThread: 0x600003d70980>{number = 1, name = main}

myQueue为并行:
start_<NSThread: 0x6000009d0a00>{number = 1, name = main}
第3次_<NSThread: 0x600000995900>{number = 6, name = (null)}
第2次_<NSThread: 0x6000009d7540>{number = 4, name = (null)}
第0次_<NSThread: 0x6000009d0a00>{number = 1, name = main}
第1次_<NSThread: 0x600000984300>{number = 7, name = (null)}
第4次_<NSThread: 0x6000009852c0>{number = 5, name = (null)}
end_<NSThread: 0x6000009d0a00>{number = 1, name = main}
  • 用于重复执行某个任务
  • 任务队列是串行队列时,重复执行的任务会按顺序执行
  • 任务队列是并行队列时,重复执行的任务会并发执行

6、dispatch_semaphore_create & dispatch_semaphore_wait & dispatch_semaphore_signal

- (void)GCDSemaphor {
    NSLog(@"start_%@",[NSThread currentThread]);
    
    dispatch_queue_t myQueue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_SERIAL);
    //创建信号量,初始值不能小于0
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
    
    //重复执行
    dispatch_apply(5, myQueue, ^(size_t i) {
        //等待降低信号量,也就是信号量-1
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        NSLog(@"第%@次_%@",@(i),[NSThread currentThread]);
        //提高信号量,也就是信号量+1
        dispatch_semaphore_signal(semaphore);
    });
    NSLog(@"end_%@",[NSThread currentThread]);
}
start_<NSThread: 0x600003bf0bc0>{number = 1, name = main}
第0次_<NSThread: 0x600003bf0bc0>{number = 1, name = main}
第1次_<NSThread: 0x600003bf0bc0>{number = 1, name = main}
第2次_<NSThread: 0x600003bf0bc0>{number = 1, name = main}
第3次_<NSThread: 0x600003bf0bc0>{number = 1, name = main}
第4次_<NSThread: 0x600003bf0bc0>{number = 1, name = main}
end_<NSThread: 0x600003bf0bc0>{number = 1, name = main}

异步任务使用

- (void)GCDSemaphorAsync {
    NSLog(@"start_%@",[NSThread currentThread]);
    
    dispatch_queue_t myQueue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_CONCURRENT);
    //创建信号量
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    
    dispatch_async(myQueue, ^{
        NSLog(@"第一次任务开始_%@",[NSThread currentThread]);
        [NSThread sleepForTimeInterval:2];
        NSLog(@"第一次任务结束_%@",[NSThread currentThread]);
        //会将信号量的值加一
        dispatch_semaphore_signal(semaphore);
    });
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    
    dispatch_async(myQueue, ^{
        NSLog(@"第二次任务开始_%@",[NSThread currentThread]);
        [NSThread sleepForTimeInterval:2];
        NSLog(@"第二次任务结束_%@",[NSThread currentThread]);
        //会将信号量的值加一
        dispatch_semaphore_signal(semaphore);
    });
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    
    dispatch_async(myQueue, ^{
        NSLog(@"第三次任务开始_%@",[NSThread currentThread]);
        [NSThread sleepForTimeInterval:2];
        NSLog(@"第三次任务结束_%@",[NSThread currentThread]);
        //会将信号量的值加一
        dispatch_semaphore_signal(semaphore);
    });
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    
    NSLog(@"end_%@",[NSThread currentThread]);
}
start_<NSThread: 0x600002eb0a00>{number = 1, name = main}
第一次任务开始_<NSThread: 0x600002eb9f40>{number = 6, name = (null)}
第一次任务结束_<NSThread: 0x600002eb9f40>{number = 6, name = (null)}
第二次任务开始_<NSThread: 0x600002eb9f40>{number = 6, name = (null)}
第二次任务结束_<NSThread: 0x600002eb9f40>{number = 6, name = (null)}
第三次任务开始_<NSThread: 0x600002eb9f40>{number = 6, name = (null)}
第三次任务结束_<NSThread: 0x600002eb9f40>{number = 6, name = (null)}
end_<NSThread: 0x600002eb0a00>{number = 1, name = main}
  • dispatch_semaphore_create创建信号量,初始值不能小于0
  • dispatch_semaphore_wait等待降低信号量,也就是信号量-1
  • dispatch_semaphore_signal提高信号量,也就是信号量+1
  • dispatch_semaphore_waitdispatch_semaphore_signal通常配对使用
主要作用:
  • 保持线程同步,将异步执行任务转换为同步执行任务
  • 保证线程 安全,为线程加锁
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 161,513评论 4 369
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,312评论 1 305
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 111,124评论 0 254
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,529评论 0 217
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,937评论 3 295
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,913评论 1 224
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,084评论 2 317
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,816评论 0 205
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,593评论 1 249
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,788评论 2 253
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,267评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,601评论 3 261
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,265评论 3 241
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,158评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,953评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,066评论 2 285
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,852评论 2 277

推荐阅读更多精彩内容