iOS多线程之GCD-同步、异步、并发、串行、线程组、栅栏函数、信号量等全网最全的总结

简介: iOS多线程之GCD-同步、异步、并发、串行、线程组、栅栏函数、信号量等全网最全的总结

1. GCD简介

GCD全称:Grand Central Dispatch,译为大型的中枢调度器、纯C语言实现,提供了非常多强大的功能;

优势:旨在替代NSThread等线程技术,充分利用设备的多核。


2. GCD队列

队列(Dispatch Queue)

这里的队列指执行任务的等待队列,即用来存放任务的队列。队列是一种特殊的线性表,采用 FIFO(先进先出)的原则,即新任务总是被插入到队列的末尾,而读取任务的时候总是从队列的头部开始读取。每读取一个任务,则从队列中释放一个任务。


GCD的队列可以分为2大类型:

并发队列(Concurrent Dispatch Queue)

1)可以让多个任务并发(同时)执行(自动开启多个线程同时执行任务)

2)并发功能只有在异步(dispatch_async)函数下才有效


串行队列(Serial Dispatch Queue)

让任务一个接着一个地执行(一个任务执行完毕后,再执行下一个任务)


3. 同步、异步、并发、串行

同步和异步主要影响: 能不能开启新的线程

同步: 在当前线程中执行任务,不具备开启新线程的能力

异步: 在新的线程中执行任务,具备开启新线程的能力


并发和串行主要影响: 任务的执行方式

并发: 多个任务并发(同时)执行

串行: 一个任务执行完毕后,再执行下一个任务


4. 创建队列

可以使用 dispatch_queue_create 方法来创建队列。该方法需要传入两个参数:

第一个参数表示队列的唯一标识符

第二个参数 DISPATCH_QUEUE_SERIAL或NULL: 表示串行队列 DISPATCH_QUEUE_CONCURRENT: 表示并发队列


系统默认提供了主队列,主队列也属于一个串行队列,可通过dispatch_get_main_queue获取主队列,放在主队列中的任务都会放在主线程中执行,系统还提供了一个并发队列,dispatch_get_global_queue() 方法获得全局并发队列。

- (void)gcdCreateQueue {
    dispatch_queue_t queue1 = dispatch_queue_create("com.glt.test.queue1", DISPATCH_QUEUE_CONCURRENT);
    dispatch_queue_t queue2 = dispatch_queue_create("com.glt.test.queue2", DISPATCH_QUEUE_SERIAL);
    dispatch_queue_t queue3 = dispatch_queue_create("com.glt.test.queue3", NULL);
    dispatch_queue_t queue4 = dispatch_get_main_queue();
    dispatch_queue_t queue5 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    NSLog(@"%@", queue1);
    NSLog(@"%@", queue2);
    NSLog(@"%@", queue3);
    NSLog(@"%@", queue4);
    NSLog(@"%@", queue5);
}
- (void)gcdCreateQueue {
    dispatch_queue_t queue1 = dispatch_queue_create("com.glt.test.queue1", DISPATCH_QUEUE_CONCURRENT);
    dispatch_queue_t queue2 = dispatch_queue_create("com.glt.test.queue2", DISPATCH_QUEUE_SERIAL);
    dispatch_queue_t queue3 = dispatch_queue_create("com.glt.test.queue3", NULL);
    dispatch_queue_t queue4 = dispatch_get_main_queue();
    dispatch_queue_t queue5 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    NSLog(@"%@", queue1);
    NSLog(@"%@", queue2);
    NSLog(@"%@", queue3);
    NSLog(@"%@", queue4);
    NSLog(@"%@", queue5);
}

运行结果:

2021-04-10 10:51:46.206755+0800 GCD[1482:45167] <OS_dispatch_queue_concurrent: com.glt.test.queue1>
2021-04-10 10:51:46.206850+0800 GCD[1482:45167] <OS_dispatch_queue_serial: com.glt.test.queue2>
2021-04-10 10:51:46.206930+0800 GCD[1482:45167] <OS_dispatch_queue_serial: com.glt.test.queue3>
2021-04-10 10:51:46.207000+0800 GCD[1482:45167] <OS_dispatch_queue_main: com.apple.main-thread>
2021-04-10 10:51:46.207061+0800 GCD[1482:45167] <OS_dispatch_queue_global: com.apple.root.default-qos>

5. 创建任务

dispatch_sync创建同步任务,dispatch_async创建异步线程任务

- (void)gcdCreateTask {
    dispatch_queue_t queue = dispatch_queue_create("com.glt.test.queue1", DISPATCH_QUEUE_CONCURRENT);
    dispatch_sync(queue, ^{
        NSLog(@"同步任务队列");
    });
    dispatch_async(queue, ^{
        NSLog(@"异步任务队列");
    });
}
- (void)gcdCreateTask {
    dispatch_queue_t queue = dispatch_queue_create("com.glt.test.queue1", DISPATCH_QUEUE_CONCURRENT);
    dispatch_sync(queue, ^{
        NSLog(@"同步任务队列");
    });
    dispatch_async(queue, ^{
        NSLog(@"异步任务队列");
    });
}


6. 队列组合

不同的队列组合产生的效果和影响不同,具体总结如下:

接下来通过样例来分别看一下组合效果(文末附源码工程链接):

1)同步+串行

不会开启新的线程、把任务添加到当前线程中、任务一个接一个的执行


- (void)syncSerial {
    dispatch_queue_t queue = dispatch_queue_create("com.glt.test", DISPATCH_QUEUE_SERIAL);
    dispatch_sync(queue, ^{
        NSLog(@"任务1");
        NSLog(@"当前线程: %@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        sleep(2);
        NSLog(@"任务2");
        NSLog(@"当前线程: %@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"任务3");
        NSLog(@"当前线程: %@", [NSThread currentThread]);
    });
}- (void)syncSerial {
    dispatch_queue_t queue = dispatch_queue_create("com.glt.test", DISPATCH_QUEUE_SERIAL);
    dispatch_sync(queue, ^{
        NSLog(@"任务1");
        NSLog(@"当前线程: %@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        sleep(2);
        NSLog(@"任务2");
        NSLog(@"当前线程: %@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"任务3");
        NSLog(@"当前线程: %@", [NSThread currentThread]);
    });
}

运行结果:

2021-04-10 10:57:25.460191+0800 GCD[1540:51156] 任务1
2021-04-10 10:57:25.460303+0800 GCD[1540:51156] 当前线程: <NSThread: 0x60000294c180>{number = 1, name = main}
2021-04-10 10:57:27.460477+0800 GCD[1540:51156] 任务2
2021-04-10 10:57:27.460732+0800 GCD[1540:51156] 当前线程: <NSThread: 0x60000294c180>{number = 1, name = main}
2021-04-10 10:57:27.460895+0800 GCD[1540:51156] 任务3
2021-04-10 10:57:27.461054+0800 GCD[1540:51156] 当前线程: <NSThread: 0x60000294c180>{number = 1, name = main}
2021-04-10 10:57:25.460191+0800 GCD[1540:51156] 任务1
2021-04-10 10:57:25.460303+0800 GCD[1540:51156] 当前线程: <NSThread: 0x60000294c180>{number = 1, name = main}
2021-04-10 10:57:27.460477+0800 GCD[1540:51156] 任务2
2021-04-10 10:57:27.460732+0800 GCD[1540:51156] 当前线程: <NSThread: 0x60000294c180>{number = 1, name = main}
2021-04-10 10:57:27.460895+0800 GCD[1540:51156] 任务3
2021-04-10 10:57:27.461054+0800 GCD[1540:51156] 当前线程: <NSThread: 0x60000294c180>{number = 1, name = main}

2)同步+并发

不会开启新的线程、把任务添加到当前线程中、任务一个接一个的执行、并发队列在异步任务中才有效



- (void)syncConcurrent {
    dispatch_queue_t queue = dispatch_queue_create("com.glt.test", DISPATCH_QUEUE_CONCURRENT);
    dispatch_sync(queue, ^{
        NSLog(@"任务1");
        NSLog(@"当前线程: %@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        sleep(2);
        NSLog(@"任务2");
        NSLog(@"当前线程: %@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"任务3");
        NSLog(@"当前线程: %@", [NSThread currentThread]);
    });
}
- (void)syncConcurrent {
    dispatch_queue_t queue = dispatch_queue_create("com.glt.test", DISPATCH_QUEUE_CONCURRENT);
    dispatch_sync(queue, ^{
        NSLog(@"任务1");
        NSLog(@"当前线程: %@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        sleep(2);
        NSLog(@"任务2");
        NSLog(@"当前线程: %@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"任务3");
        NSLog(@"当前线程: %@", [NSThread currentThread]);
    });
}

运行结果:

2021-04-10 11:00:59.308934+0800 GCD[1570:54003] 任务1
2021-04-10 11:00:59.309035+0800 GCD[1570:54003] 当前线程: <NSThread: 0x6000031b81c0>{number = 1, name = main}
2021-04-10 11:01:01.309702+0800 GCD[1570:54003] 任务2
2021-04-10 11:01:01.309948+0800 GCD[1570:54003] 当前线程: <NSThread: 0x6000031b81c0>{number = 1, name = main}
2021-04-10 11:01:01.310101+0800 GCD[1570:54003] 任务3
2021-04-10 11:01:01.310262+0800 GCD[1570:54003] 当前线程: <NSThread: 0x6000031b81c0>{number = 1, name = main}

3)异步+串行

会开启新的线程、把任务添加到当前线程中、任务一个接一个的执行


- (void)asyncSerial {
    dispatch_queue_t queue = dispatch_queue_create("com.glt.test", DISPATCH_QUEUE_SERIAL);
    dispatch_async(queue, ^{
        NSLog(@"任务1");
        NSLog(@"当前线程: %@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        sleep(2);
        NSLog(@"任务2");
        NSLog(@"当前线程: %@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"任务3");
        NSLog(@"当前线程: %@", [NSThread currentThread]);
    });
}
- (void)asyncSerial {
    dispatch_queue_t queue = dispatch_queue_create("com.glt.test", DISPATCH_QUEUE_SERIAL);
    dispatch_async(queue, ^{
        NSLog(@"任务1");
        NSLog(@"当前线程: %@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        sleep(2);
        NSLog(@"任务2");
        NSLog(@"当前线程: %@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"任务3");
        NSLog(@"当前线程: %@", [NSThread currentThread]);
    });
}

运行结果:

2021-04-10 11:04:22.612780+0800 GCD[1612:57386] 任务1
2021-04-10 11:04:22.612881+0800 GCD[1612:57386] 当前线程: <NSThread: 0x6000009a2a40>{number = 5, name = (null)}
2021-04-10 11:04:24.615244+0800 GCD[1612:57386] 任务2
2021-04-10 11:04:24.615514+0800 GCD[1612:57386] 当前线程: <NSThread: 0x6000009a2a40>{number = 5, name = (null)}
2021-04-10 11:04:24.615686+0800 GCD[1612:57386] 任务3
2021-04-10 11:04:24.615854+0800 GCD[1612:57386] 当前线程: <NSThread: 0x6000009a2a40>{number = 5, name = (null)}

4)异步+并发

会开启新的线程、把任务添加到新的线程中、并发的执行任务


- (void)asyncConcurrent {
    dispatch_queue_t queue = dispatch_queue_create("com.glt.test", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(queue, ^{
        NSLog(@"任务1 - %@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        sleep(2);
        NSLog(@"任务2 - %@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"任务3 - %@", [NSThread currentThread]);
    });
}

运行结果:

2021-04-10 11:09:06.322720+0800 GCD[1664:61535] 任务1 - <NSThread: 0x6000002d1700>{number = 6, name = (null)}
2021-04-10 11:09:06.322726+0800 GCD[1664:61536] 任务3 - <NSThread: 0x6000002c5e80>{number = 7, name = (null)}
2021-04-10 11:09:08.326379+0800 GCD[1664:61541] 任务2 - <NSThread: 0x60000029a840>{number = 4, name = (null)}2021-04-10 11:09:06.322720+0800 GCD[1664:61535] 任务1 - <NSThread: 0x6000002d1700>{number = 6, name = (null)}
2021-04-10 11:09:06.322726+0800 GCD[1664:61536] 任务3 - <NSThread: 0x6000002c5e80>{number = 7, name = (null)}
2021-04-10 11:09:08.326379+0800 GCD[1664:61541] 任务2 - <NSThread: 0x60000029a840>{number = 4, name = (null)}

5)同步+主队列

不会开启新的线程、把任务添加到当前线程中、产生死锁(2和3相互等待产生死锁)


- (void)syncMain {
//    dispatch_queue_t queue = dispatch_queue_create("com.glt.test", DISPATCH_QUEUE_SERIAL);//不会产生死锁
    dispatch_queue_t queue = dispatch_get_main_queue();//产生死锁
    NSLog(@"1");
    dispatch_sync(queue, ^{
        NSLog(@"2");
    });
    NSLog(@"3");
}
- (void)syncMain {
//    dispatch_queue_t queue = dispatch_queue_create("com.glt.test", DISPATCH_QUEUE_SERIAL);//不会产生死锁
    dispatch_queue_t queue = dispatch_get_main_queue();//产生死锁
    NSLog(@"1");
    dispatch_sync(queue, ^{
        NSLog(@"2");
    });
    NSLog(@"3");
}

运行结果:


2021-04-10 11:11:30.578822+0800 GCD[1694:64014] 1

6)异步+主队列

不会开启新的线程、把任务添加到当前线程中、任务一个接一个的执行

- (void)asyncMain {
    dispatch_queue_t queue = dispatch_get_main_queue();
    NSLog(@"1");
    dispatch_async(queue, ^{
        NSLog(@"2");
    });
    NSLog(@"3");
}

运行结果:

2021-04-10 11:24:34.478703+0800 GCD[1755:73277] 1
2021-04-10 11:24:34.478825+0800 GCD[1755:73277] 3
2021-04-10 11:24:34.481464+0800 GCD[1755:73277] 2
2021-04-10 11:24:34.478703+0800 GCD[1755:73277] 1
2021-04-10 11:24:34.478825+0800 GCD[1755:73277] 3
2021-04-10 11:24:34.481464+0800 GCD[1755:73277] 2

7)同步+全局队列

会开启新的线程、把任务添加到当前线程中、没有开启新的线程、任务一个接一个的执行

- (void)syncGlobal {
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_sync(queue, ^{
        NSLog(@"任务1");
        NSLog(@"当前线程: %@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        sleep(2);
        NSLog(@"任务2");
        NSLog(@"当前线程: %@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"任务3");
        NSLog(@"当前线程: %@", [NSThread currentThread]);
    });
}
- (void)syncGlobal {
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_sync(queue, ^{
        NSLog(@"任务1");
        NSLog(@"当前线程: %@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        sleep(2);
        NSLog(@"任务2");
        NSLog(@"当前线程: %@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"任务3");
        NSLog(@"当前线程: %@", [NSThread currentThread]);
    });
}

运行结果:

2021-04-10 11:26:45.632522+0800 GCD[1778:75212] 任务1
2021-04-10 11:26:45.632626+0800 GCD[1778:75212] 当前线程: <NSThread: 0x600003910900>{number = 1, name = main}
2021-04-10 11:26:47.633010+0800 GCD[1778:75212] 任务2
2021-04-10 11:26:47.633255+0800 GCD[1778:75212] 当前线程: <NSThread: 0x600003910900>{number = 1, name = main}
2021-04-10 11:26:47.633437+0800 GCD[1778:75212] 任务3
2021-04-10 11:26:47.633594+0800 GCD[1778:75212] 当前线程: <NSThread: 0x600003910900>{number = 1, name = main}

8)异步+全局队列

会开启新的线程、把任务添加到新的线程中、并发的执行任务

- (void)asyncGlobal {
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(queue, ^{
        NSLog(@"任务1 - %@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        sleep(2);
        NSLog(@"任务2 - %@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"任务3 - %@", [NSThread currentThread]);
    });
}
- (void)asyncGlobal {
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(queue, ^{
        NSLog(@"任务1 - %@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        sleep(2);
        NSLog(@"任务2 - %@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"任务3 - %@", [NSThread currentThread]);
    });
}

运行结果:

2021-04-10 11:30:37.836797+0800 GCD[1814:79285] 任务1 - <NSThread: 0x6000032fac40>{number = 4, name = (null)}
2021-04-10 11:30:37.836805+0800 GCD[1814:79287] 任务3 - <NSThread: 0x6000032a96c0>{number = 6, name = (null)}
2021-04-10 11:30:39.836879+0800 GCD[1814:79283] 任务2 - <NSThread: 0x6000032a9080>{number = 7, name = (null)}

9)串行+异步+同步

死锁


- (void)concurrentSyncAsync {
    dispatch_queue_t queue = dispatch_queue_create("com.glt.test.queue1", DISPATCH_QUEUE_SERIAL);
    NSLog(@"1");
    dispatch_async(queue, ^{
        NSLog(@"4");
        dispatch_sync(queue, ^{
            NSLog(@"2");
        });
        NSLog(@"3");
    });
    NSLog(@"5");
}

运行结果:

2021-04-10 11:33:34.234259+0800 GCD[1834:81537] 1
2021-04-10 11:33:34.234365+0800 GCD[1834:81537] 5
2021-04-10 11:33:34.234377+0800 GCD[1834:81712] 4
2021-04-10 11:33:34.234259+0800 GCD[1834:81537] 1
2021-04-10 11:33:34.234365+0800 GCD[1834:81537] 5
2021-04-10 11:33:34.234377+0800 GCD[1834:81712] 4


7. 线程间通信

子线程执行耗时操作(图片下载、图片合成、文件下载等),回到主线程刷新UI

- (void)gcdMessage {
    NSLog(@"1");
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        sleep(2);
        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"2-刷新UI");
        });
    });
    NSLog(@"3");
}
- (void)gcdMessage {
    NSLog(@"1");
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        sleep(2);
        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"2-刷新UI");
        });
    });
    NSLog(@"3");
}

运行结果:

2021-04-10 11:39:23.991812+0800 GCD[1865:85789] 1
2021-04-10 11:39:23.991908+0800 GCD[1865:85789] 3
2021-04-10 11:39:25.992573+0800 GCD[1865:85789] 2-刷新UI2021-04-10 11:39:23.991812+0800 GCD[1865:85789] 1
2021-04-10 11:39:23.991908+0800 GCD[1865:85789] 3
2021-04-10 11:39:25.992573+0800 GCD[1865:85789] 2-刷新UI

8. 栅栏函数

栅栏函数:dispatch_barrier_async会等待前边追加到并发队列中的任务全部执行完毕之后,再将指定的任务追加到该异步队列中;并且栅栏函数只能使用自己创建的并发队列、全局队列没有效果(使用全局队列相当于普通的异步任务),如果是主队列则依次执行;

dispatch_barrier_sync与dispatch_barrier_sync区别是:dispatch_barrier_sync内部的函数是在主线程中执行,dispatch_barrier_sync执行的任务是在新开辟的子线程中执行;

- (void)barrierTask {
    dispatch_queue_t queue = dispatch_queue_create("com.glt.test", DISPATCH_QUEUE_CONCURRENT);//栅栏函数有效果
//    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);//栅栏函数无效果
//    dispatch_queue_t queue = dispatch_get_main_queue();//栅栏函数有效果、队列依次执行
    dispatch_async(queue, ^{
        NSLog(@"任务1 - %@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        sleep(2);
        NSLog(@"任务2 - %@", [NSThread currentThread]);
    });
    dispatch_barrier_sync(queue, ^{
        sleep(4);
        NSLog(@"栅栏任务 - %@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"任务3 - %@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"任务4 - %@", [NSThread currentThread]);
    });
}
- (void)barrierTask {
    dispatch_queue_t queue = dispatch_queue_create("com.glt.test", DISPATCH_QUEUE_CONCURRENT);//栅栏函数有效果
//    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);//栅栏函数无效果
//    dispatch_queue_t queue = dispatch_get_main_queue();//栅栏函数有效果、队列依次执行
    dispatch_async(queue, ^{
        NSLog(@"任务1 - %@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        sleep(2);
        NSLog(@"任务2 - %@", [NSThread currentThread]);
    });
    dispatch_barrier_sync(queue, ^{
        sleep(4);
        NSLog(@"栅栏任务 - %@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"任务3 - %@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"任务4 - %@", [NSThread currentThread]);
    });
}

运行结果:

2021-04-10 11:44:44.907322+0800 GCD[1923:90606] 任务1 - <NSThread: 0x600000f3cdc0>{number = 6, name = (null)}
2021-04-10 11:44:46.911944+0800 GCD[1923:90607] 任务2 - <NSThread: 0x600000f2e2c0>{number = 5, name = (null)}
2021-04-10 11:44:50.913348+0800 GCD[1923:90420] 栅栏任务 - <NSThread: 0x600000f60900>{number = 1, name = main}
2021-04-10 11:44:50.913659+0800 GCD[1923:90609] 任务4 - <NSThread: 0x600000f64fc0>{number = 4, name = (null)}
2021-04-10 11:44:50.913642+0800 GCD[1923:90607] 任务3 - <NSThread: 0x600000f2e2c0>{number = 5, name = (null)}


9. 延时执行任务

- (void)gcdAfter {
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        NSLog(@"延时执行任务");
    });
}
- (void)gcdAfter {
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        NSLog(@"延时执行任务");
    });
}


10. dispatch_once_t

仅执行1次,多线程环境下保证线程安全,注意:如果将onceToken设置为0,下次再调用依旧会执行,常用于销毁单例

- (void)gcdOnce {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        NSLog(@"only one");
    });
}


11. dispatch_apply

按照指定的次数将指定的任务追加到指定的队列中,并等待全部队列执行结束,无论是在串行队列,还是并发队列中,dispatch_apply 都会等待全部任务执行完毕


- (void)gcdApply {
    dispatch_queue_t queue = dispatch_queue_create("com.glt.test", DISPATCH_QUEUE_CONCURRENT);
    NSLog(@"begain");
    dispatch_apply(6, queue, ^(size_t time) {
        NSLog(@"%zu - %@", time, [NSThread currentThread]);
    });
    NSLog(@"end");
}

运行结果:


2021-04-10 11:56:20.440608+0800 GCD[1959:97881] begain
2021-04-10 11:56:20.440731+0800 GCD[1959:97881] 0 - <NSThread: 0x600002b94a00>{number = 1, name = main}
2021-04-10 11:56:20.440806+0800 GCD[1959:98094] 1 - <NSThread: 0x600002bd5680>{number = 3, name = (null)}
2021-04-10 11:56:20.440815+0800 GCD[1959:97881] 3 - <NSThread: 0x600002b94a00>{number = 1, name = main}
2021-04-10 11:56:20.440816+0800 GCD[1959:98090] 2 - <NSThread: 0x600002b99980>{number = 6, name = (null)}
2021-04-10 11:56:20.440839+0800 GCD[1959:98093] 4 - <NSThread: 0x600002bd5980>{number = 5, name = (null)}
2021-04-10 11:56:20.440837+0800 GCD[1959:98089] 5 - <NSThread: 0x600002bcc880>{number = 4, name = (null)}
2021-04-10 11:56:20.440918+0800 GCD[1959:97881] end
2021-04-10 11:56:20.440608+0800 GCD[1959:97881] begain
2021-04-10 11:56:20.440731+0800 GCD[1959:97881] 0 - <NSThread: 0x600002b94a00>{number = 1, name = main}
2021-04-10 11:56:20.440806+0800 GCD[1959:98094] 1 - <NSThread: 0x600002bd5680>{number = 3, name = (null)}
2021-04-10 11:56:20.440815+0800 GCD[1959:97881] 3 - <NSThread: 0x600002b94a00>{number = 1, name = main}
2021-04-10 11:56:20.440816+0800 GCD[1959:98090] 2 - <NSThread: 0x600002b99980>{number = 6, name = (null)}
2021-04-10 11:56:20.440839+0800 GCD[1959:98093] 4 - <NSThread: 0x600002bd5980>{number = 5, name = (null)}
2021-04-10 11:56:20.440837+0800 GCD[1959:98089] 5 - <NSThread: 0x600002bcc880>{number = 4, name = (null)}
2021-04-10 11:56:20.440918+0800 GCD[1959:97881] end


12. 线程组

1)dispatch_group_async: 先把任务放到队列中,然后将队列放入队列组中

2)dispatch_group_notify: 监听dispatch_group_async中任务的完成状态,当所有的任务都执行完成后,最后执行dispatch_group_notify内部的任务

3)dispatch_group_wait: 阻塞当前任务,会先执行等待之前的任务完成后,再执行等待后的任务

4)dispatch_group_enter会将任务数+1,dispatch_group_leave会将任务数-1,当任务数为0的时候再执行dispatch_group_notify中的任务

场景描述:我们要等前3个任务完成以后再执行其他的任务,并且这3个任务内部又有回到其他线程的操作


- (void)gcdGroup {
    dispatch_group_t group = dispatch_group_create();
    dispatch_queue_t queue = dispatch_queue_create("com.glt.test", DISPATCH_QUEUE_CONCURRENT);
    dispatch_group_enter(group);
    dispatch_group_async(group, queue, ^{
        NSLog(@"任务1 - %@", [NSThread currentThread]);
        dispatch_group_leave(group);
    });
    dispatch_group_enter(group);
    dispatch_group_async(group, queue, ^{
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            NSLog(@"任务2 - %@", [NSThread currentThread]);
            dispatch_group_leave(group);
        });
    });
//    dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
    dispatch_group_enter(group);
    dispatch_group_async(group, queue, ^{
        NSLog(@"任务3 - %@", [NSThread currentThread]);
        dispatch_group_leave(group);
    });
    dispatch_group_notify(group, queue, ^{
        NSLog(@"任务执行完毕 - %@", [NSThread currentThread]);
    });
}
- (void)gcdGroup {
    dispatch_group_t group = dispatch_group_create();
    dispatch_queue_t queue = dispatch_queue_create("com.glt.test", DISPATCH_QUEUE_CONCURRENT);
    dispatch_group_enter(group);
    dispatch_group_async(group, queue, ^{
        NSLog(@"任务1 - %@", [NSThread currentThread]);
        dispatch_group_leave(group);
    });
    dispatch_group_enter(group);
    dispatch_group_async(group, queue, ^{
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            NSLog(@"任务2 - %@", [NSThread currentThread]);
            dispatch_group_leave(group);
        });
    });
//    dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
    dispatch_group_enter(group);
    dispatch_group_async(group, queue, ^{
        NSLog(@"任务3 - %@", [NSThread currentThread]);
        dispatch_group_leave(group);
    });
    dispatch_group_notify(group, queue, ^{
        NSLog(@"任务执行完毕 - %@", [NSThread currentThread]);
    });
}

运行结果:

2021-04-10 12:00:52.647107+0800 GCD[1989:101516] 任务3 - <NSThread: 0x60000097e9c0>{number = 4, name = (null)}
2021-04-10 12:00:52.647116+0800 GCD[1989:101520] 任务1 - <NSThread: 0x600000940f40>{number = 6, name = (null)}
2021-04-10 12:00:55.647281+0800 GCD[1989:101346] 任务2 - <NSThread: 0x6000009501c0>{number = 1, name = main}
2021-04-10 12:00:55.647530+0800 GCD[1989:101516] 任务执行完毕 - <NSThread: 0x60000097e9c0>{number = 4, name = (null)}
2021-04-10 12:00:52.647107+0800 GCD[1989:101516] 任务3 - <NSThread: 0x60000097e9c0>{number = 4, name = (null)}
2021-04-10 12:00:52.647116+0800 GCD[1989:101520] 任务1 - <NSThread: 0x600000940f40>{number = 6, name = (null)}
2021-04-10 12:00:55.647281+0800 GCD[1989:101346] 任务2 - <NSThread: 0x6000009501c0>{number = 1, name = main}
2021-04-10 12:00:55.647530+0800 GCD[1989:101516] 任务执行完毕 - <NSThread: 0x60000097e9c0>{number = 4, name = (null)}

13. 信号量

dispatch_semaphore_create:创建一个Semaphore并设置信号的总量;

dispatch_semaphore_signal:发送信号,让信号+1;

dispatch_semaphore_wait:可以使总信号量-1,信号总量小于0时就会等待,阻塞所在线程;

dispatch_semaphore作用:

1)保持线程同步,将异步执行任务转换为同步执行任务

2保证线程安全,为线程加锁


- (void)gcdSemaphoreSync {
    NSInteger ret = [self gcdRet];
    NSLog(@"异步获取函数返回值 - %ld", ret);
}
- (NSInteger)gcdRet {
    __block NSInteger count = 0;
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    dispatch_queue_t queue = dispatch_queue_create("com.glt.test", DISPATCH_QUEUE_CONCURRENT);
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), queue, ^{//模拟异步网络请求
        count = 999;
        dispatch_semaphore_signal(semaphore);//+1后为0则继续向下执行
    });
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);//-1后小于0开始阻塞等待
    return count;
}
//保证线程安全,为线程加锁
- (void)gcdSemaphoreLock {
    if (!_semaphore) {
        _semaphore = dispatch_semaphore_create(1);
    }
    dispatch_queue_t queue = dispatch_queue_create("com.glt.test", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(queue, ^{
        dispatch_semaphore_wait(self->_semaphore, DISPATCH_TIME_FOREVER);//-1后等于0开始向下进行,之后再执行到这里此处会小于0,产生阻塞,会等待解锁后继续向下执行
        NSLog(@"线程锁-begain");
        sleep(3);
        NSLog(@"线程锁-end");
        dispatch_semaphore_signal(self->_semaphore);//+1后为0,解锁,则继续执行
    });
}

方法调用:


  [self gcdSemaphoreSync];
    [self gcdSemaphoreLock];
    [self gcdSemaphoreLock];
    [self gcdSemaphoreLock];  [self gcdSemaphoreSync];
    [self gcdSemaphoreLock];
    [self gcdSemaphoreLock];
    [self gcdSemaphoreLock];

运行结果:


2021-04-10 12:04:02.670569+0800 GCD[2009:103890] 异步获取函数返回值 - 999
2021-04-10 12:04:02.670715+0800 GCD[2009:104065] 线程锁-begain
2021-04-10 12:04:05.671743+0800 GCD[2009:104065] 线程锁-end
2021-04-10 12:04:05.672013+0800 GCD[2009:104062] 线程锁-begain
2021-04-10 12:04:08.677301+0800 GCD[2009:104062] 线程锁-end
2021-04-10 12:04:08.677575+0800 GCD[2009:104064] 线程锁-begain
2021-04-10 12:04:11.678193+0800 GCD[2009:104064] 线程锁-end
2021-04-10 12:04:02.670569+0800 GCD[2009:103890] 异步获取函数返回值 - 999
2021-04-10 12:04:02.670715+0800 GCD[2009:104065] 线程锁-begain
2021-04-10 12:04:05.671743+0800 GCD[2009:104065] 线程锁-end
2021-04-10 12:04:05.672013+0800 GCD[2009:104062] 线程锁-begain
2021-04-10 12:04:08.677301+0800 GCD[2009:104062] 线程锁-end
2021-04-10 12:04:08.677575+0800 GCD[2009:104064] 线程锁-begain
2021-04-10 12:04:11.678193+0800 GCD[2009:104064] 线程锁-end

源码:https://github.com/gltwy/public

相关文章
|
3月前
|
安全 算法 Java
Java 多线程:线程安全与同步控制的深度解析
本文介绍了 Java 多线程开发的关键技术,涵盖线程的创建与启动、线程安全问题及其解决方案,包括 synchronized 关键字、原子类和线程间通信机制。通过示例代码讲解了多线程编程中的常见问题与优化方法,帮助开发者提升程序性能与稳定性。
140 0
|
3月前
|
Java API 调度
从阻塞到畅通:Java虚拟线程开启并发新纪元
从阻塞到畅通:Java虚拟线程开启并发新纪元
302 83
|
3月前
|
存储 Java 调度
Java虚拟线程:轻量级并发的革命性突破
Java虚拟线程:轻量级并发的革命性突破
253 83
|
5月前
|
机器学习/深度学习 消息中间件 存储
【高薪程序员必看】万字长文拆解Java并发编程!(9-2):并发工具-线程池
🌟 ​大家好,我是摘星!​ 🌟今天为大家带来的是并发编程中的强力并发工具-线程池,废话不多说让我们直接开始。
189 0
|
3月前
|
数据采集 监控 调度
干货分享“用 多线程 爬取数据”:单线程 + 协程的效率反超 3 倍,这才是 Python 异步的正确打开方式
在 Python 爬虫中,多线程因 GIL 和切换开销效率低下,而协程通过用户态调度实现高并发,大幅提升爬取效率。本文详解协程原理、实战对比多线程性能,并提供最佳实践,助你掌握异步爬虫核心技术。
|
4月前
|
Java 数据挖掘 调度
Java 多线程创建零基础入门新手指南:从零开始全面学习多线程创建方法
本文从零基础角度出发,深入浅出地讲解Java多线程的创建方式。内容涵盖继承`Thread`类、实现`Runnable`接口、使用`Callable`和`Future`接口以及线程池的创建与管理等核心知识点。通过代码示例与应用场景分析,帮助读者理解每种方式的特点及适用场景,理论结合实践,轻松掌握Java多线程编程 essentials。
245 5
|
11月前
|
开发框架 前端开发 Android开发
安卓与iOS开发中的跨平台策略
在移动应用开发的战场上,安卓和iOS两大阵营各据一方。随着技术的演进,跨平台开发框架成为开发者的新宠,旨在实现一次编码、多平台部署的梦想。本文将探讨跨平台开发的优势与挑战,并分享实用的开发技巧,帮助开发者在安卓和iOS的世界中游刃有余。
|
9月前
|
iOS开发 开发者
uniapp开发ios打包Error code = -5000 Error message: Error: certificate file(p12) import failed!报错问题如何解决
uniapp开发ios打包Error code = -5000 Error message: Error: certificate file(p12) import failed!报错问题如何解决
490 67
uniapp开发ios打包Error code = -5000 Error message: Error: certificate file(p12) import failed!报错问题如何解决
|
8月前
|
JavaScript 搜索推荐 Android开发
【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
244 8
【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
|
10月前
|
iOS开发 开发者 MacOS
深入探索iOS开发中的SwiftUI框架
【10月更文挑战第21天】 本文将带领读者深入了解Apple最新推出的SwiftUI框架,这一革命性的用户界面构建工具为iOS开发者提供了一种声明式、高效且直观的方式来创建复杂的用户界面。通过分析SwiftUI的核心概念、主要特性以及在实际项目中的应用示例,我们将展示如何利用SwiftUI简化UI代码,提高开发效率,并保持应用程序的高性能和响应性。无论你是iOS开发的新手还是有经验的开发者,本文都将为你提供宝贵的见解和实用的指导。
288 66