iOS浅谈多线程之GCD
2018-10-10 本文已影响6人
元宝是只小肥猫
名称 | 功能特点 | 确定性解释 | 不确定性解释 |
---|---|---|---|
同步 | 完成需要做的任务后才会返回,进行下一任务 | “任务”,在 GCD 里指的是 Block;在 performSelector 方法中,对应 selector 方法。</p>同步方法,功能类似 dispatch_group_wait ,而 group 指的是所有线程,包括主线程。 |
</p> 不一定是多线程 |
异步 | 不会等待任务完成才返回,会立即返回。 | 异步是多线程的代名词,因为必定会开启新的线程,线程的申请是由异步负责,起到开分支的作用。 | -- |
串行队列 | 任务依次执行 | 同一时间队列中只有一个任务在执行,每个任务只有在前一个任务执行完成后才能开始执行。 | 你不知道在一个Block(任务)执行结束到下一个Block(任务)开始执行之间的这段时间时间是多长 |
并行队列 | 任务并发执行 | 你唯一能保证的是,这些任务会按照被添加的顺序开始执行。但是任务可以以任何顺序完成 | 你不知道在执行下一个任务是从什么时候开始,或者说任意时刻有多个Block(任务)运行,这个完全是取决于GCD。 |
全局队列 | 隶属于并行队列 | 不要与 barrier 栅栏方法搭配使用, barrier 只有与自定义的并行队列一起使用,才能让 barrier 达到我们所期望的栅栏功能。与 串行队列或者 global 队列 一起使用,barrier 的表现会和 dispatch_sync 方法一样。 | |
主队列 | 隶属于串行队列 | 不能与 sync 同步方法搭配使用,会造成死循环 |
易混淆解决办法:先区分同步还是异步。同步不具备开启新线程的能力,block立即执行;异步具备开启新线程的能力,block不会立即执行,而是等到整个代码块执行完毕再执行;
创建队列
1、创建串行队列
/*!
* @const DISPATCH_QUEUE_SERIAL
*
* @discussion A dispatch queue that invokes blocks serially in FIFO order.
*/
#define DISPATCH_QUEUE_SERIAL NULL
dispatch_queue_t queue = dispatch_queue_create("abc", DISPATCH_QUEUE_SERIAL);
2、创建并发队列
dispatch_queue_t queue = dispatch_queue_create("abc", DISPATCH_QUEUE_CONCURRENT);
同步+串行
- (void)test1 {
NSLog(@"00000000000000");
//创建串行队列
dispatch_queue_t serial_queue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL);
//创建同步队列+ 串行
dispatch_sync(serial_queue, ^{
NSLog(@"----%@",[NSThread currentThread]);
});
dispatch_sync(serial_queue, ^{
NSLog(@"++++%@",[NSThread currentThread]);
});
NSLog(@"....................");
}
同步+并发
- (void)test1 {
NSLog(@"00000000000000");
//创建并发队列
dispatch_queue_t concurrent_queue = dispatch_queue_create(NULL, DISPATCH_QUEUE_CONCURRENT);
//因为是同步队列,代码块会立即执行
dispatch_sync(concurrent_queue, ^{
for (int i = 0; i < 5; i++) {
NSLog(@"----%@",[NSThread currentThread]);
}
});
//因为是同步队列,代码块会立即执行
dispatch_sync(concurrent_queue, ^{
for (int i = 0; i < 5; i++) {
NSLog(@"++++%@",[NSThread currentThread]);
}
});
NSLog(@"....................");
}
2018-10-09 19:21:12.694600+0800 Visit_Thread[8135:426834] 00000000000000
2018-10-09 19:21:12.694806+0800 Visit_Thread[8135:426834] ----<NSThread: 0x600000261b40>{number = 1, name = main}
2018-10-09 19:21:12.695614+0800 Visit_Thread[8135:426834] ----<NSThread: 0x600000261b40>{number = 1, name = main}
2018-10-09 19:21:12.695793+0800 Visit_Thread[8135:426834] ----<NSThread: 0x600000261b40>{number = 1, name = main}
2018-10-09 19:21:12.695899+0800 Visit_Thread[8135:426834] ----<NSThread: 0x600000261b40>{number = 1, name = main}
2018-10-09 19:21:12.696062+0800 Visit_Thread[8135:426834] ----<NSThread: 0x600000261b40>{number = 1, name = main}
2018-10-09 19:21:12.696172+0800 Visit_Thread[8135:426834] ++++<NSThread: 0x600000261b40>{number = 1, name = main}
2018-10-09 19:21:12.696379+0800 Visit_Thread[8135:426834] ++++<NSThread: 0x600000261b40>{number = 1, name = main}
2018-10-09 19:21:12.696613+0800 Visit_Thread[8135:426834] ++++<NSThread: 0x600000261b40>{number = 1, name = main}
2018-10-09 19:21:12.697533+0800 Visit_Thread[8135:426834] ++++<NSThread: 0x600000261b40>{number = 1, name = main}
2018-10-09 19:21:12.697787+0800 Visit_Thread[8135:426834] ++++<NSThread: 0x600000261b40>{number = 1, name = main}
2018-10-09 19:21:12.698354+0800 Visit_Thread[8135:426834] ....................
异步 + 串行:只会开启一条线程,在代码块执行完毕后,在子线程中会顺序执行。
- (void)test1 {
NSLog(@"00000000000000");
//创建串行队列
dispatch_queue_t serial_queue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL);
//异步队列,可能立即执行代码块,也可能不立即执行代码块(在子线程中它会第一个执行)
dispatch_async(serial_queue, ^{
NSLog(@"111111%@",[NSThread currentThread]);
});
//异步队列,可能立即执行代码块,也可能不立即执行代码块
dispatch_async(serial_queue, ^{
NSLog(@"222222%@",[NSThread currentThread]);
});
dispatch_async(serial_queue, ^{
NSLog(@"333333%@",[NSThread currentThread]);
});
dispatch_async(serial_queue, ^{
NSLog(@"444444%@",[NSThread currentThread]);
});
for (int i = 0; i < 100; i++) {
}
NSLog(@"....................");
}
2018-10-09 19:40:51.339314+0800 Visit_Thread[8476:450796] 00000000000000
2018-10-09 19:40:51.339696+0800 Visit_Thread[8476:450796] ....................
2018-10-09 19:40:51.339752+0800 Visit_Thread[8476:455374] 111111<NSThread: 0x60400027c400>{number = 6, name = (null)}
2018-10-09 19:40:51.340142+0800 Visit_Thread[8476:455374] 222222<NSThread: 0x60400027c400>{number = 6, name = (null)}
2018-10-09 19:40:51.340272+0800 Visit_Thread[8476:455374] 333333<NSThread: 0x60400027c400>{number = 6, name = (null)}
2018-10-09 19:40:51.340381+0800 Visit_Thread[8476:455374] 444444<NSThread: 0x60400027c400>{number = 6, name = (null)}
异步 + 并发
- (void)test1 {
NSLog(@"00000000000000");
//创建并发队列
dispatch_queue_t concurrent_queue = dispatch_queue_create(NULL, DISPATCH_QUEUE_CONCURRENT);
//创建异步队列,具备开启新线程的能力,并且代码不会立即执行,而是等到代码块执行完毕后在执行block
dispatch_async(concurrent_queue, ^{
for (int i = 0; i < 5; i++) {
NSLog(@"----%@",[NSThread currentThread]);
}
});
dispatch_async(concurrent_queue, ^{
for (int i = 0; i < 5; i++) {
NSLog(@"++++%@",[NSThread currentThread]);
}
});
NSLog(@"....................");
}
2018-10-09 19:45:27.725315+0800 Visit_Thread[8658:462540] 00000000000000
2018-10-09 19:45:27.725499+0800 Visit_Thread[8658:462540] ....................
2018-10-09 19:45:27.725643+0800 Visit_Thread[8658:462600] ----<NSThread: 0x6000002765c0>{number = 3, name = (null)}
2018-10-09 19:45:27.725643+0800 Visit_Thread[8658:462602] ++++<NSThread: 0x604000470d40>{number = 4, name = (null)}
2018-10-09 19:45:27.725811+0800 Visit_Thread[8658:462600] ----<NSThread: 0x6000002765c0>{number = 3, name = (null)}
2018-10-09 19:45:27.725819+0800 Visit_Thread[8658:462602] ++++<NSThread: 0x604000470d40>{number = 4, name = (null)}
2018-10-09 19:45:27.726026+0800 Visit_Thread[8658:462600] ----<NSThread: 0x6000002765c0>{number = 3, name = (null)}
2018-10-09 19:45:27.726216+0800 Visit_Thread[8658:462602] ++++<NSThread: 0x604000470d40>{number = 4, name = (null)}
2018-10-09 19:45:27.726343+0800 Visit_Thread[8658:462600] ----<NSThread: 0x6000002765c0>{number = 3, name = (null)}
2018-10-09 19:45:27.726429+0800 Visit_Thread[8658:462602] ++++<NSThread: 0x604000470d40>{number = 4, name = (null)}
2018-10-09 19:45:27.726547+0800 Visit_Thread[8658:462600] ----<NSThread: 0x6000002765c0>{number = 3, name = (null)}
2018-10-09 19:45:27.727120+0800 Visit_Thread[8658:462602] ++++<NSThread: 0x604000470d40>{number = 4, name = (null)}
队列的“获取与创建”
并发队列
- (void)test1 {
//“创建”并发队列(这是自己创建的)
dispatch_queue_t concurrent_queue = dispatch_queue_create(NULL, DISPATCH_QUEUE_CONCURRENT);
//“获取”并发队列(在GCD中原本就存在一个全局队列,每次获取的地址都是固定的)
dispatch_queue_t global_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
NSLog(@"%p____%p",concurrent_queue,global_queue);
}
2018-10-09 20:06:16.159774+0800 Visit_Thread[9049:483747] 0x604000158d60____0x112c8b500
2018-10-09 20:06:17.726835+0800 Visit_Thread[9049:483747] 0x604000157d90____0x112c8b500
2018-10-09 20:06:18.873916+0800 Visit_Thread[9049:483747] 0x604000158d60____0x112c8b500
2018-10-09 20:06:20.193030+0800 Visit_Thread[9049:483747] 0x604000157d90____0x112c8b500
2018-10-09 20:06:21.359897+0800 Visit_Thread[9049:483747] 0x604000158d60____0x112c8b500
2018-10-09 20:06:22.086049+0800 Visit_Thread[9049:483747] 0x6000001589f0____0x112c8b500
获取主队列
异步 + 主队列
- (void)test1 {
NSLog(@"start");
//"获取"主队列,凡是主队列的任务,都会在主线程执行
//所以,即使是异步队列,拥有开线程的能力,也不会开新的线程,而仍然在主线程中执行。
//但需要注意的是,因为是异步,所以block块不会立即执行,
//而是等代码块执行完毕后再回到主线程执行
dispatch_queue_t main_queue = dispatch_get_main_queue();
dispatch_async(main_queue, ^{
NSLog(@"------%@",[NSThread currentThread]);
});
dispatch_async(main_queue, ^{
NSLog(@"+++++%@",[NSThread currentThread]);
});
NSLog(@"end");
}
2018-10-09 21:41:16.654290+0800 Visit_Thread[10396:550901] start
2018-10-09 21:41:16.654503+0800 Visit_Thread[10396:550901] end
2018-10-09 21:41:16.654860+0800 Visit_Thread[10396:550901] ------<NSThread: 0x6000000705c0>{number = 1, name = main}
2018-10-09 21:41:16.655154+0800 Visit_Thread[10396:550901] +++++<NSThread: 0x6000000705c0>{number = 1, name = main}
同步 + 主队列(程序崩溃)Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x
- (void)test1 {
NSLog(@"start");
//"获取"主队列,凡是主队列的任务,都会在主线程执行
dispatch_queue_t main_queue = dispatch_get_main_queue();
//因为是同步队列,不拥有开线程的能力,代码会立即执行(当前是主线程,所以在主线程中执行)
//但是主线程正在读取代码块,造成死锁(知道是抢夺同一块资源,但如何科学严谨的解释,还是不太明白)
dispatch_sync(main_queue, ^{
NSLog(@"------%@",[NSThread currentThread]);
});
dispatch_sync(main_queue, ^{
NSLog(@"+++++%@",[NSThread currentThread]);
});
NSLog(@"end");
}
2018-10-09 22:11:16.219673+0800 Visit_Thread[11137:584090] start
如果将test1方法在子线程中执行,则不会发生死锁。
[NSThread detachNewThreadSelector:@selector(test1) toTarget:self withObject:nil];
2018-10-09 22:18:17.573527+0800 Visit_Thread[11258:591492] start
2018-10-09 22:18:17.573980+0800 Visit_Thread[11258:591405] ------<NSThread: 0x60400007be40>{number = 1, name = main}
2018-10-09 22:18:17.574300+0800 Visit_Thread[11258:591405] +++++<NSThread: 0x60400007be40>{number = 1, name = main}
2018-10-09 22:18:17.574635+0800 Visit_Thread[11258:591492] end
使用GCD实现线程间的通信
- (void)downloadImgFromURL:(NSString *)URL {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
NSData *data = [[NSData alloc]initWithContentsOfURL:[NSURL URLWithString:URL]];
UIImage *img = [[UIImage alloc]initWithData:data];
if (img) {
// [self performSelectorOnMainThread:@selector(updateUI:) withObject:img waitUntilDone:YES];
dispatch_async(dispatch_get_main_queue(), ^{
//
});
}
});
}
GCD常用函数
延迟执行
//第一种
[self performSelector:@selector(test1) withObject:nil afterDelay:2];
//第二种
[NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(test1) userInfo:nil repeats:NO];
//第三种(可以更改队列)
//DISPATCH_TIME_NOW:从现在开始计算时间
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
//code
});
使用dispatch_once控制block在应用程序运行过程只执行一次(多用于单例)
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
//code
});
GCD栅栏函数
- (void)test1 {
NSLog(@"00000000000000");
//若想使用栅栏函数控制执行顺序,必须要使用自己创建的并发队列,不然不生效
// dispatch_queue_t global_queue = dispatch_get_global_queue(0, 0);
//创建并发队列
dispatch_queue_t concurrent_queue = dispatch_queue_create(NULL, DISPATCH_QUEUE_CONCURRENT);
//创建异步队列,具备开启新线程的能力,并且代码不会立即执行,而是等到代码块执行完毕后在执行block
dispatch_async(concurrent_queue, ^{
for (int i = 0; i < 5; i++) {
NSLog(@"11111%@",[NSThread currentThread]);
}
});
dispatch_async(concurrent_queue, ^{
// dispatch_barrier_async(concurrent_queue, ^{
for (int i = 0; i < 5; i++) {
NSLog(@"22222%@",[NSThread currentThread]);
}
});
dispatch_async(concurrent_queue, ^{
// dispatch_barrier_async(concurrent_queue, ^{
for (int i = 0; i < 5; i++) {
NSLog(@"33333%@",[NSThread currentThread]);
}
});
// dispatch_async(concurrent_queue, ^{
dispatch_barrier_async(concurrent_queue, ^{
for (int i = 0; i < 5; i++) {
NSLog(@"44444%@",[NSThread currentThread]);
}
});
dispatch_async(concurrent_queue, ^{
// dispatch_barrier_async(concurrent_queue, ^{
for (int i = 0; i < 5; i++) {
NSLog(@"55555%@",[NSThread currentThread]);
}
});
NSLog(@"....................");
}
2018-10-09 23:08:22.697358+0800 Visit_Thread[12047:641271] 00000000000000
2018-10-09 23:08:22.697750+0800 Visit_Thread[12047:641271] ....................
2018-10-09 23:08:22.697928+0800 Visit_Thread[12047:641332] 33333<NSThread: 0x604000271480>{number = 5, name = (null)}
2018-10-09 23:08:22.697941+0800 Visit_Thread[12047:641331] 11111<NSThread: 0x60000027a780>{number = 3, name = (null)}
2018-10-09 23:08:22.697950+0800 Visit_Thread[12047:641334] 22222<NSThread: 0x60000027e140>{number = 4, name = (null)}
2018-10-09 23:08:22.698274+0800 Visit_Thread[12047:641331] 11111<NSThread: 0x60000027a780>{number = 3, name = (null)}
2018-10-09 23:08:22.698297+0800 Visit_Thread[12047:641334] 22222<NSThread: 0x60000027e140>{number = 4, name = (null)}
2018-10-09 23:08:22.698314+0800 Visit_Thread[12047:641332] 33333<NSThread: 0x604000271480>{number = 5, name = (null)}
2018-10-09 23:08:22.699046+0800 Visit_Thread[12047:641331] 11111<NSThread: 0x60000027a780>{number = 3, name = (null)}
2018-10-09 23:08:22.699050+0800 Visit_Thread[12047:641334] 22222<NSThread: 0x60000027e140>{number = 4, name = (null)}
2018-10-09 23:08:22.699944+0800 Visit_Thread[12047:641332] 33333<NSThread: 0x604000271480>{number = 5, name = (null)}
2018-10-09 23:08:22.704314+0800 Visit_Thread[12047:641331] 11111<NSThread: 0x60000027a780>{number = 3, name = (null)}
2018-10-09 23:08:22.704673+0800 Visit_Thread[12047:641334] 22222<NSThread: 0x60000027e140>{number = 4, name = (null)}
2018-10-09 23:08:22.705165+0800 Visit_Thread[12047:641332] 33333<NSThread: 0x604000271480>{number = 5, name = (null)}
2018-10-09 23:08:22.705566+0800 Visit_Thread[12047:641331] 11111<NSThread: 0x60000027a780>{number = 3, name = (null)}
2018-10-09 23:08:22.705843+0800 Visit_Thread[12047:641334] 22222<NSThread: 0x60000027e140>{number = 4, name = (null)}
2018-10-09 23:08:22.706073+0800 Visit_Thread[12047:641332] 33333<NSThread: 0x604000271480>{number = 5, name = (null)}
2018-10-09 23:08:22.708688+0800 Visit_Thread[12047:641334] 44444<NSThread: 0x60000027e140>{number = 4, name = (null)}
2018-10-09 23:08:22.709592+0800 Visit_Thread[12047:641334] 44444<NSThread: 0x60000027e140>{number = 4, name = (null)}
2018-10-09 23:08:22.711425+0800 Visit_Thread[12047:641334] 44444<NSThread: 0x60000027e140>{number = 4, name = (null)}
2018-10-09 23:08:22.714273+0800 Visit_Thread[12047:641334] 44444<NSThread: 0x60000027e140>{number = 4, name = (null)}
2018-10-09 23:08:22.714664+0800 Visit_Thread[12047:641334] 44444<NSThread: 0x60000027e140>{number = 4, name = (null)}
2018-10-09 23:08:22.715315+0800 Visit_Thread[12047:641334] 55555<NSThread: 0x60000027e140>{number = 4, name = (null)}
2018-10-09 23:08:22.715944+0800 Visit_Thread[12047:641334] 55555<NSThread: 0x60000027e140>{number = 4, name = (null)}
2018-10-09 23:08:22.716174+0800 Visit_Thread[12047:641334] 55555<NSThread: 0x60000027e140>{number = 4, name = (null)}
2018-10-09 23:08:22.716467+0800 Visit_Thread[12047:641334] 55555<NSThread: 0x60000027e140>{number = 4, name = (null)}
2018-10-09 23:08:22.716631+0800 Visit_Thread[12047:641334] 55555<NSThread: 0x60000027e140>{number = 4, name = (null)}
说明:给谁加栅栏,那么它前面的队列执行完毕后自己才执行。
GCD的快速迭代
- (void)test3 {
/**
* 第一个参数:遍历的次数
* 第二个参数:队列
* 第三个参数:index索引
*/
dispatch_apply(10, dispatch_get_global_queue(0, 0), ^(size_t index) {
NSLog(@"%@————————%zu",[NSThread currentThread],index);
});
}
2018-10-09 23:40:43.773924+0800 Visit_Thread[12576:670073] <NSThread: 0x600000070540>{number = 1, name = main}————————1
2018-10-09 23:40:43.773924+0800 Visit_Thread[12576:670199] <NSThread: 0x600000277600>{number = 5, name = (null)}————————3
2018-10-09 23:40:43.773974+0800 Visit_Thread[12576:670132] <NSThread: 0x60000026ef00>{number = 3, name = (null)}————————0
2018-10-09 23:40:43.773976+0800 Visit_Thread[12576:670193] <NSThread: 0x604000276180>{number = 4, name = (null)}————————2
2018-10-09 23:40:43.774169+0800 Visit_Thread[12576:670073] <NSThread: 0x600000070540>{number = 1, name = main}————————4
2018-10-09 23:40:43.774169+0800 Visit_Thread[12576:670199] <NSThread: 0x600000277600>{number = 5, name = (null)}————————5
2018-10-09 23:40:43.774196+0800 Visit_Thread[12576:670132] <NSThread: 0x60000026ef00>{number = 3, name = (null)}————————6
2018-10-09 23:40:43.774208+0800 Visit_Thread[12576:670193] <NSThread: 0x604000276180>{number = 4, name = (null)}————————7
2018-10-09 23:40:43.774275+0800 Visit_Thread[12576:670073] <NSThread: 0x600000070540>{number = 1, name = main}————————8
2018-10-09 23:40:43.774301+0800 Visit_Thread[12576:670199] <NSThread: 0x600000277600>{number = 5, name = (null)}————————9
小案例:
- (void)test3 {
NSString *from = @"/Users/szphsw4/Desktop/test";
NSString *to = @"/Users/szphsw4/Desktop/11";
NSArray *subPath = [[NSFileManager defaultManager]subpathsAtPath:from];
NSLog(@"%@",subPath);
NSInteger count = subPath.count;
/**
* 第一个参数:遍历的次数
* 第二个参数:队列
* 第三个参数:index索引
*/
dispatch_apply(count, dispatch_get_global_queue(0, 0), ^(size_t index) {
NSLog(@"%@————————%zu",[NSThread currentThread],index);
NSString *fullFrom = [from stringByAppendingPathComponent:subPath[index]];
NSString *fullTo = [to stringByAppendingPathComponent:subPath[index]];
[[NSFileManager defaultManager]moveItemAtPath:fullFrom toPath:fullTo error:nil];
});
}
2018-10-09 23:58:33.738883+0800 Visit_Thread[12897:687725] (
"index.html",
"desk.php",
"userconfig.php",
"wx.php",
"rqtest.php",
"echo.php",
"alarm.php",
"9c804efcc8f5cc4989bd07dcb7d31484.php",
de,
"de/index.html",
"de/.DS_Store",
"de/index.php",
"de/css",
"de/css/index.css",
"de/.idea",
"de/.idea/inspectionProfiles",
"de/.idea/\U8bbe\U5907\U5217\U8868.iml",
"de/.idea/workspace.xml",
"de/.idea/modules.xml",
"zp.php",
"2.jpg"
)
2018-10-09 23:58:33.739196+0800 Visit_Thread[12897:687725] <NSThread: 0x604000076b00>{number = 1, name = main}————————0
2018-10-09 23:58:33.739196+0800 Visit_Thread[12897:687842] <NSThread: 0x60000027fe80>{number = 3, name = (null)}————————1
2018-10-09 23:58:33.739274+0800 Visit_Thread[12897:687843] <NSThread: 0x60000027fb40>{number = 4, name = (null)}————————2
2018-10-09 23:58:33.739274+0800 Visit_Thread[12897:687844] <NSThread: 0x60000027f200>{number = 5, name = (null)}————————3
2018-10-09 23:58:33.741803+0800 Visit_Thread[12897:687725] <NSThread: 0x604000076b00>{number = 1, name = main}————————4
2018-10-09 23:58:33.741860+0800 Visit_Thread[12897:687844] <NSThread: 0x60000027f200>{number = 5, name = (null)}————————5
2018-10-09 23:58:33.741932+0800 Visit_Thread[12897:687843] <NSThread: 0x60000027fb40>{number = 4, name = (null)}————————6
2018-10-09 23:58:33.742049+0800 Visit_Thread[12897:687842] <NS2018-10-09 23:58:33.742403+0800 Visit_Thread[12897:687725] <NSThread: 0x604000076b00>{number = 1, name = main}————————8
Thread: 0x60000027fe80>{number = 3, name = (null)}————————7
2018-10-09 23:58:33.742437+0800 Visit_Thread[12897:687844] <NSThread: 0x60000027f200>{number = 5, name = (null)}————————9
2018-10-09 23:58:33.742742+0800 Visit_Thread[12897:687843] <NSThread: 0x60000027fb40>{number = 4, name = (null)}————————10
2018-10-09 23:58:33.756019+0800 Visit_Thread[12897:687725] <NSThread: 0x604000076b00>{number = 1, name = main}————————11
2018-10-09 23:58:33.756019+0800 Visit_Thread[12897:687842] <NSThread: 0x60000027fe80>{number = 3, name = (null)}————————12
2018-10-09 23:58:33.816421+0800 Visit_Thread[12897:687725] <NSThread: 0x604000076b00>{number = 1, name = main}————————14
2018-10-09 23:58:33.816285+0800 Visit_Thread[12897:687844] <NSThread: 0x60000027f200>{number = 5, name = (null)}————————13
2018-10-09 23:58:33.816421+0800 Visit_Thread[12897:687842] <NSThread: 0x60000027fe80>{number = 3, name = (null)}————————15
2018-10-09 23:58:33.816476+0800 Visit_Thread[12897:687843] <NSThread: 0x60000027fb40>{number = 4, name = (null)}————————16
2018-10-09 23:58:33.817187+0800 Visit_Thread[12897:687725] <NSThread: 0x604000076b00>{number = 1, name = main}————————17
2018-10-09 23:58:33.817678+0800 Visit_Thread[12897:687842] <NSThread: 0x60000027fe80>{number = 3, name = (null)}————————18
2018-10-09 23:58:33.817727+0800 Visit_Thread[12897:687844] <NSThread: 0x60000027f200>{number = 5, name = (null)}————————19
2018-10-09 23:58:33.818176+0800 Visit_Thread[12897:687843] <NSThread: 0x60000027fb40>{number = 4, name = (null)}————————20
GCD队列的使用
dispatch_group_notify是异步的,不会阻塞线程
方式1:
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
//创建队列组
dispatch_group_t group = dispatch_group_create();
//将任务添加到队列
dispatch_group_async(group, queue, ^{
NSLog(@"1-----%@",[NSThread currentThread]);
});
dispatch_group_async(group, queue, ^{
NSLog(@"2-----%@",[NSThread currentThread]);
});
dispatch_group_async(group, queue, ^{
NSLog(@"3-----%@",[NSThread currentThread]);
});
//当组中的所有任务执行完毕后调用该方法
dispatch_group_notify(group, queue, ^{
NSLog(@"执行完毕");
});
2018-10-10 08:39:50.472617+0800 Visit_Thread[1182:27050] 2-----<NSThread: 0x604000266040>{number = 11, name = (null)}
2018-10-10 08:39:50.472651+0800 Visit_Thread[1182:26979] 1-----<NSThread: 0x604000268cc0>{number = 10, name = (null)}
2018-10-10 08:39:50.472695+0800 Visit_Thread[1182:27049] 3-----<NSThread: 0x604000267580>{number = 12, name = (null)}
2018-10-10 08:39:50.473912+0800 Visit_Thread[1182:27049] 执行完毕
方式2:
- (void)test4 {
NSLog(@"代码块开始");
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
//创建队列组
dispatch_group_t group = dispatch_group_create();
//进入群组
dispatch_group_enter(group);
dispatch_async(queue, ^{
NSLog(@"1-----%@",[NSThread currentThread]);
dispatch_group_leave(group);
});
//离开群组
dispatch_group_enter(group);
dispatch_async(queue, ^{
NSLog(@"2-----%@",[NSThread currentThread]);
dispatch_group_leave(group);
});
dispatch_group_enter(group);
dispatch_async(queue, ^{
NSLog(@"3-----%@",[NSThread currentThread]);
dispatch_group_leave(group);
});
//当组中的所有任务执行完毕后调用该方法
dispatch_group_notify(group, queue, ^{
NSLog(@"执行完毕");
});
NSLog(@"代码块结束");
}
2018-10-10 09:06:53.037015+0800 Visit_Thread[1480:48196] 代码块开始
2018-10-10 09:06:53.038101+0800 Visit_Thread[1480:48196] 代码块结束
2018-10-10 09:06:53.038300+0800 Visit_Thread[1480:48248] 3-----<NSThread: 0x600000276c80>{number = 5, name = (null)}
2018-10-10 09:06:53.038301+0800 Visit_Thread[1480:48247] 2-----<NSThread: 0x600000277040>{number = 4, name = (null)}
2018-10-10 09:06:53.038306+0800 Visit_Thread[1480:48246] 1-----<NSThread: 0x6040002797c0>{number = 3, name = (null)}
2018-10-10 09:06:53.039638+0800 Visit_Thread[1480:48246] 执行完毕
使用阻塞方式监听
- (void)test4 {
NSLog(@"代码块开始");
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
//创建队列组
dispatch_group_t group = dispatch_group_create();
//进入群组
dispatch_group_enter(group);
dispatch_async(queue, ^{
NSLog(@"1-----%@",[NSThread currentThread]);
dispatch_group_leave(group);
});
//离开群组
dispatch_group_enter(group);
dispatch_async(queue, ^{
NSLog(@"2-----%@",[NSThread currentThread]);
dispatch_group_leave(group);
});
dispatch_group_enter(group);
dispatch_async(queue, ^{
NSLog(@"3-----%@",[NSThread currentThread]);
dispatch_group_leave(group);
});
//使用阻塞方式
//死等,直到队列组中的所有任务执行完毕才能执行
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
NSLog(@"代码块结束");
}
2018-10-10 09:11:06.201841+0800 Visit_Thread[1528:54087] 代码块开始
2018-10-10 09:11:06.202185+0800 Visit_Thread[1528:54136] 1-----<NSThread: 0x600000460a40>{number = 3, name = (null)}
2018-10-10 09:11:06.202190+0800 Visit_Thread[1528:54137] 3-----<NSThread: 0x604000463140>{number = 5, name = (null)}
2018-10-10 09:11:06.202191+0800 Visit_Thread[1528:54135] 2-----<NSThread: 0x604000462f80>{number = 4, name = (null)}
2018-10-10 09:11:06.202572+0800 Visit_Thread[1528:54087] 代码块结束
补充
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
// 使用函数方式创建任务
dispatch_async_f(dispatch_get_global_queue(0, 0), NULL, task);
dispatch_async_f(dispatch_get_global_queue(0, 0), NULL, task);
dispatch_async_f(dispatch_get_global_queue(0, 0), NULL, task);
}
void task(void *parm) {
NSLog(@"%@",[NSThread currentThread]);
}