一、GCD的队列有两种,一种是串行队列,一种是并发队列。
1.串行队列:
任务按往队列里的添加先后顺序执行,先进先出(FIFO),前一个任务执行完再开始执行下一个任务。(我们开发中主线程队列就是一个串行队列,所以我们经常在主线程写的一般任务(不考虑多线程),都是顺序执行的)。
** 注意一个串行队列里只有一个线程 **。
2.并发队列:
任务会在这个队列中新开线程,并发同时执行(无序)。
我们GCD使用常伴有dispatch_sync
和dispatch_async
,这就是同步执行和异步执行。
二、执行方式:同步和异步
1.同步执行:任务都在当前线程中执行,执行过程中会阻塞当前线程。
2.异步执行:任务会开辟新的线程,并在新的线程中执行,不会阻塞当前线程。
** 注意 **
1.同步执行没有开启新线程的能力, 所有的任务都只能在当前线程执行;
2.异步执行有开启新线程的能力, 但是, 有开启新线程的能力, 也不一定会利用这种能力, 也就是说, 异步执行是否开启新线程, 需要具体问题具体分析;
3.并发队列中的任务会放到不同的线程中去执行;
4.串行队列中的任务只会放到同一线程中去执行.
组合起来:
1).串行队列同步执行:任务都在当前线程执行(同步),并且顺序执行(串行)
2).串行队列异步执行:任务都在开辟的新的子线程中执行(异步),并且顺序执行(串行)
3).并发队列同步执行:任务都在当前线程执行(同步),但是是顺序执行的(并没有体现并发的特性)
4).并发队列异步执行:任务在开辟的多个子线程中执行(异步),并且是同时执行的(并发)
三、代码实践:队列和执行方式组合
1.串行队列 - 同步执行
//1.串行队列-同步执行
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");
打印结果:
2023-09-07 11:40:58.147911+0800 虚拟定位[52431:1256240] task1
2023-09-07 11:40:58.148068+0800 虚拟定位[52431:1256240] task1---<_NSMainThread: 0x6000021b8480>{number = 1, name = main}
2023-09-07 11:40:58.148179+0800 虚拟定位[52431:1256240] task2
2023-09-07 11:40:58.148323+0800 虚拟定位[52431:1256240] task2---<_NSMainThread: 0x6000021b8480>{number = 1, name = main}
2023-09-07 11:40:58.148608+0800 虚拟定位[52431:1256240] task3
2023-09-07 11:40:58.149013+0800 虚拟定位[52431:1256240] task3---<_NSMainThread: 0x6000021b8480>{number = 1, name = main}
2023-09-07 11:40:58.149264+0800 虚拟定位[52431:1256240] task4
2023-09-07 11:40:58.149473+0800 虚拟定位[52431:1256240] task4---<_NSMainThread: 0x6000021b8480>{number = 1, name = main}
//若在viewDidLoad新开启一个子线程,结果是一样的
[NSThread detachNewThreadSelector:@selector(clickConsoleLog) toTarget:self withObject:nil];
分析:任务是在当前线程(当前是主线程)顺序执行的
验证结果:串行队列同步执行:任务都在当前线程执行(同步),并且顺序执行(串行)
这里需要注意的是代码直接在viewDidLoad里写的,主队列也是一个串行队列,但在主线程中使用主队列同步执行会造成死锁
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]);
打印结果:
2023-09-07 11:48:59.317367+0800 虚拟定位[52769:1263549] task4
2023-09-07 11:48:59.317378+0800 虚拟定位[52769:1263756] task1
2023-09-07 11:48:59.317487+0800 虚拟定位[52769:1263549] task4---<_NSMainThread: 0x6000021f4600>{number = 1, name = main}
2023-09-07 11:48:59.317556+0800 虚拟定位[52769:1263756] task1---<NSThread: 0x6000021ea6c0>{number = 6, name = (null)}
2023-09-07 11:48:59.317980+0800 虚拟定位[52769:1263756] task2
2023-09-07 11:48:59.318185+0800 虚拟定位[52769:1263756] task2---<NSThread: 0x6000021ea6c0>{number = 6, name = (null)}
2023-09-07 11:48:59.318415+0800 虚拟定位[52769:1263756] task3
2023-09-07 11:48:59.318676+0800 虚拟定位[52769:1263756] task3---<NSThread: 0x6000021ea6c0>{number = 6, name = (null)}
分析:主线程异步调用,我们先分析加到队列里的task任务1、2、3,确实都是在开辟了的新线程{number = 3, name = (null)}上顺序执行的,关于task4,由于是异步的,它也没加入队列queue,啥时候输出就看电脑心情
验证结果: 串行队列异步执行:任务都在开辟的新的子线程中执行(异步),并且顺序执行(串行)
这里需要注意,由于新创建了串行线程,所以任务会在新开辟的线程上执行,若是直接在主队列异步调用,任务执行都在主线程上。
dispatch_queue_t queue_2 = dispatch_get_main_queue();
dispatch_async(queue_2, ^{
NSLog(@"task1");
NSLog(@"task1---%@",[NSThread currentThread]);
});
dispatch_async(queue_2, ^{
NSLog(@"task2");
NSLog(@"task2---%@",[NSThread currentThread]);
});
dispatch_async(queue_2, ^{
NSLog(@"task3");
NSLog(@"task3---%@",[NSThread currentThread]);
});
NSLog(@"task4");
NSLog(@"task4---%@",[NSThread currentThread]);
打印结果:
2023-09-07 11:56:12.817566+0800 虚拟定位[53133:1270516] task4
2023-09-07 11:56:12.817695+0800 虚拟定位[53133:1270516] task4---<_NSMainThread: 0x6000032b8140>{number = 1, name = main}
2023-09-07 11:56:12.818165+0800 虚拟定位[53133:1270516] task1
2023-09-07 11:56:12.818308+0800 虚拟定位[53133:1270516] task1---<_NSMainThread: 0x6000032b8140>{number = 1, name = main}
2023-09-07 11:56:12.818430+0800 虚拟定位[53133:1270516] task2
2023-09-07 11:56:12.818556+0800 虚拟定位[53133:1270516] task2---<_NSMainThread: 0x6000032b8140>{number = 1, name = main}
2023-09-07 11:56:12.818672+0800 虚拟定位[53133:1270516] task3
2023-09-07 11:56:12.824585+0800 虚拟定位[53133:1270516] task3---<_NSMainThread: 0x6000032b8140>{number = 1, name = main}
3.并发队列 - 同步执行
dispatch_queue_t queue_3 = dispatch_queue_create("concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_sync(queue_3, ^{
NSLog(@"task1");
NSLog(@"task1---%@",[NSThread currentThread]);
});
dispatch_sync(queue_3, ^{
NSLog(@"task2");
NSLog(@"task2---%@",[NSThread currentThread]);
});
dispatch_sync(queue_3, ^{
NSLog(@"task3");
NSLog(@"task3---%@",[NSThread currentThread]);
});
NSLog(@"task4");
NSLog(@"task4---%@",[NSThread currentThread]);
打印结果:
2023-09-07 12:02:38.767374+0800 虚拟定位[53480:1277012] task1
2023-09-07 12:02:38.767506+0800 虚拟定位[53480:1277012] task1---<_NSMainThread: 0x6000038ac000>{number = 1, name = main}
2023-09-07 12:02:38.767600+0800 虚拟定位[53480:1277012] task2
2023-09-07 12:02:38.767719+0800 虚拟定位[53480:1277012] task2---<_NSMainThread: 0x6000038ac000>{number = 1, name = main}
2023-09-07 12:02:38.767861+0800 虚拟定位[53480:1277012] task3
2023-09-07 12:02:38.768231+0800 虚拟定位[53480:1277012] task3---<_NSMainThread: 0x6000038ac000>{number = 1, name = main}
2023-09-07 12:02:38.768362+0800 虚拟定位[53480:1277012] task4
2023-09-07 12:02:38.768675+0800 虚拟定位[53480:1277012] task4---<_NSMainThread: 0x6000038ac000>{number = 1, name = main}
分析:任务是在当前线程(是主线程没有开辟新线程)顺序执行的,跟串行同步一样,虽是并发队列,却不能并发
验证结果: 并发队列同步执行:任务都在当前线程执行(同步),但是是顺序执行的(并没有体现并发的特性)
4.并发队列 - 异步执行
dispatch_queue_t queue_3 = dispatch_queue_create("concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue_3, ^{
NSLog(@"task1");
NSLog(@"task1---%@",[NSThread currentThread]);
});
dispatch_async(queue_3, ^{
NSLog(@"task2");
NSLog(@"task2---%@",[NSThread currentThread]);
});
dispatch_async(queue_3, ^{
NSLog(@"task3");
NSLog(@"task3---%@",[NSThread currentThread]);
});
NSLog(@"task4");
NSLog(@"task4---%@",[NSThread currentThread]);
打印结果:
2023-09-07 12:06:54.146885+0800 虚拟定位[53698:1280648] task4
2023-09-07 12:06:54.146899+0800 虚拟定位[53698:1280781] task1
2023-09-07 12:06:54.146919+0800 虚拟定位[53698:1280779] task2
2023-09-07 12:06:54.146929+0800 虚拟定位[53698:1280780] task3
2023-09-07 12:06:54.147027+0800 虚拟定位[53698:1280648] task4---<_NSMainThread: 0x600002f30480>{number = 1, name = main}
2023-09-07 12:06:54.147149+0800 虚拟定位[53698:1280781] task1---<NSThread: 0x600002f4c700>{number = 7, name = (null)}
2023-09-07 12:06:54.147892+0800 虚拟定位[53698:1280779] task2---<NSThread: 0x600002f7c680>{number = 6, name = (null)}
2023-09-07 12:06:54.148040+0800 虚拟定位[53698:1280780] task3---<NSThread: 0x600002f7c240>{number = 5, name = (null)}
2023-09-07 12:09:07.365986+0800 虚拟定位[53698:1280648] task4
2023-09-07 12:09:07.366002+0800 虚拟定位[53698:1280786] task1
2023-09-07 12:09:07.366061+0800 虚拟定位[53698:1280787] task2
2023-09-07 12:09:07.366130+0800 虚拟定位[53698:1280648] task4---<_NSMainThread: 0x600002f30480>{number = 1, name = main}
2023-09-07 12:09:07.366092+0800 虚拟定位[53698:1282794] task3
2023-09-07 12:09:07.366221+0800 虚拟定位[53698:1280786] task1---<NSThread: 0x600002f0ae00>{number = 8, name = (null)}
2023-09-07 12:09:07.366957+0800 虚拟定位[53698:1280787] task2---<NSThread: 0x600002f6d6c0>{number = 9, name = (null)}
2023-09-07 12:09:07.367243+0800 虚拟定位[53698:1282794] task3---<NSThread: 0x600002f6dc40>{number = 10, name = (null)}
2023-09-07 12:09:28.781997+0800 虚拟定位[53698:1280648] task4
2023-09-07 12:09:28.782034+0800 虚拟定位[53698:1282794] task1
2023-09-07 12:09:28.782060+0800 虚拟定位[53698:1283078] task2
2023-09-07 12:09:28.782120+0800 虚拟定位[53698:1280648] task4---<_NSMainThread: 0x600002f30480>{number = 1, name = main}
2023-09-07 12:09:28.782103+0800 虚拟定位[53698:1282796] task3
2023-09-07 12:09:28.782221+0800 虚拟定位[53698:1282794] task1---<NSThread: 0x600002f6dc40>{number = 10, name = (null)}
2023-09-07 12:09:28.782778+0800 虚拟定位[53698:1283078] task2---<NSThread: 0x600002f0a940>{number = 12, name = (null)}
2023-09-07 12:09:28.783021+0800 虚拟定位[53698:1282796] task3---<NSThread: 0x600002f0b7c0>{number = 11, name = (null)}
分析:先看task4吧,没有加入队列,所以肯定是在主线程执行的,由于异步,啥时候执行还是要看电脑心情...好了,言归正传,我们看加入到并发队列里的任务1、2、3,三个运行结果证明它们是在不同的线程中无序执行的,每个任务都开辟了新的线程去执行,并且执行顺序是无序的,体现了并发的特性。所以我们经常也是使用这种方式做一些需求
验证结果: 并发队列异步执行:任务在开辟的多个子线程中执行(异步),并且是同时执行的(并发)
网友评论