iOS 线程、队列与派发
基本概念
线程(Thread)
线程,是操作系统直接支持的执行单元,CPU 调度的基本单位,是代码执行的路径;一个进程内至少包含一个线程。
线程只拥有程序的少量资源,但是他与进程内的其他线程共享进程的整个内存空间;线程的切换速度远快于进程。
队列(Queue)
队列是用于保存以及管理任务的,队列根据情况,调度线程来执行其中的任务。
队列分为串行队列和并发队列;队列都是先进先出的。
串行队列(SerialQueue)
串行队列,需要等待前一个任务执行完成才能执行下个任务。
串行队列只需要一个线程就可以完成任务的派发。
并发队列(ConcurrentQueue)
并发队列,允许多个任务同时执行;
并发队列,任务开始执行的时间是按照顺序的,但是任务结束时间并不确定。
并发队列的并发执行,需要通过新建线程来实现
主队列
主队列,是一种的特殊的串行队列;
主队列的任务只能在主线程执行,并且需要等待主线程的 RunLoop 空闲时才能派发。
派发
GCD 的派发,分为同步派发和异步派发。
实验
设计方案
注意,因为主线程是默认环境,所以代码是默认执行在主线程的
两个线程:主线程 子线程
三个队里:主队列 串行队列 并发队列
两种派发:同步派发 异步派发
将上述进行组合,共有 2 x 3 x 2 = 12 种情况
1 2 3 4 5
| - (void)printCurrentThread { NSThread *currentThread = [NSThread currentThread]; NSLog(@"cur = %@", currentThread); }
|
实验 1:在主线程中派发任务
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
|
NSLog(@"--start--"); dispatch_queue_t mainQueue = dispatch_get_main_queue(); dispatch_sync(mainQueue, ^{ NSLog(@"task1--start"); [self printCurrentThread]; sleep(3); NSLog(@"task1--end"); }); dispatch_sync(mainQueue, ^{ NSLog(@"task2--start"); [self printCurrentThread]; NSLog(@"task2--end"); }); NSLog(@"--end--");
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
|
NSLog(@"--start--"); dispatch_queue_t mainQueue = dispatch_get_main_queue(); dispatch_async(mainQueue, ^{ NSLog(@"task1--start"); [self printCurrentThread]; sleep(3); NSLog(@"task1--end"); }); dispatch_async(mainQueue, ^{ NSLog(@"task2--start"); [self printCurrentThread]; NSLog(@"task2--end"); }); NSLog(@"--end--");
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
|
NSLog(@"--start--"); dispatch_queue_t serialQueue = dispatch_queue_create("serialQueue", DISPATCH_QUEUE_SERIAL); dispatch_sync(serialQueue, ^{ NSLog(@"task1--start"); [self printCurrentThread]; sleep(3); NSLog(@"task1--end"); }); dispatch_sync(serialQueue, ^{ NSLog(@"task2--start"); [self printCurrentThread]; NSLog(@"task2--end"); }); NSLog(@"--end--");
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
|
NSLog(@"--start--"); dispatch_queue_t serialQueue = dispatch_queue_create("serialQueue", DISPATCH_QUEUE_SERIAL); dispatch_async(serialQueue, ^{ NSLog(@"task1--start"); [self printCurrentThread]; sleep(3); NSLog(@"task1--end"); }); dispatch_async(serialQueue, ^{ NSLog(@"task2--start"); [self printCurrentThread]; NSLog(@"task2--end"); }); NSLog(@"--end--");
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
|
NSLog(@"--start--"); dispatch_queue_t concurrentQueue = dispatch_queue_create("concurrentQueue", DISPATCH_QUEUE_CONCURRENT); dispatch_sync(concurrentQueue, ^{ NSLog(@"task1--start"); [self printCurrentThread]; sleep(3); NSLog(@"task1--end"); }); dispatch_sync(concurrentQueue, ^{ NSLog(@"task2--start"); [self printCurrentThread]; NSLog(@"task2--end"); }); NSLog(@"--end--");
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
|
NSLog(@"--start--"); dispatch_queue_t concurrentQueue = dispatch_queue_create("concurrentQueue", DISPATCH_QUEUE_CONCURRENT); dispatch_async(concurrentQueue, ^{ NSLog(@"task1--start"); [self printCurrentThread]; sleep(3); NSLog(@"task1--end"); }); dispatch_async(concurrentQueue, ^{ NSLog(@"task2--start"); [self printCurrentThread]; NSLog(@"task2--end"); }); NSLog(@"--end--");
|
实验 2:在子线程派发任务
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
|
[NSThread detachNewThreadWithBlock:^{ NSLog(@"--start--"); [self printCurrentThread]; dispatch_queue_t mainQueue = dispatch_get_main_queue(); dispatch_sync(mainQueue, ^{ NSLog(@"task1--start"); [self printCurrentThread]; sleep(3); NSLog(@"task1--end"); }); dispatch_sync(mainQueue, ^{ NSLog(@"task2--start"); [self printCurrentThread]; NSLog(@"task2--end"); }); NSLog(@"--end--"); }];
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
|
[NSThread detachNewThreadWithBlock:^{ NSLog(@"--start--"); [self printCurrentThread]; dispatch_queue_t mainQueue = dispatch_get_main_queue(); dispatch_async(mainQueue, ^{ NSLog(@"task1--start"); [self printCurrentThread]; sleep(3); NSLog(@"task1--end"); }); dispatch_async(mainQueue, ^{ NSLog(@"task2--start"); [self printCurrentThread]; NSLog(@"task2--end"); }); NSLog(@"--end--"); }];
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
|
[NSThread detachNewThreadWithBlock:^{ NSLog(@"--start--"); [self printCurrentThread]; dispatch_queue_t serialQueue = dispatch_queue_create("serialQueue", DISPATCH_QUEUE_SERIAL); dispatch_sync(serialQueue, ^{ NSLog(@"task1--start"); [self printCurrentThread]; sleep(3); NSLog(@"task1--end"); }); dispatch_sync(serialQueue, ^{ NSLog(@"task2--start"); [self printCurrentThread]; NSLog(@"task2--end"); }); NSLog(@"--end--"); }];
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
|
[NSThread detachNewThreadWithBlock:^{ NSLog(@"--start--"); [self printCurrentThread]; dispatch_queue_t serialQueue = dispatch_queue_create("serialQueue", DISPATCH_QUEUE_SERIAL); dispatch_async(serialQueue, ^{ NSLog(@"task1--start"); [self printCurrentThread]; sleep(3); NSLog(@"task1--end"); }); dispatch_async(serialQueue, ^{ NSLog(@"task2--start"); [self printCurrentThread]; NSLog(@"task2--end"); }); NSLog(@"--end--"); }];
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
|
[NSThread detachNewThreadWithBlock:^{ NSLog(@"--start--"); [self printCurrentThread]; dispatch_queue_t concurrentQueue = dispatch_queue_create("concurrentQueue", DISPATCH_QUEUE_CONCURRENT); dispatch_sync(concurrentQueue, ^{ NSLog(@"task1--start"); [self printCurrentThread]; sleep(3); NSLog(@"task1--end"); }); dispatch_sync(concurrentQueue, ^{ NSLog(@"task2--start"); [self printCurrentThread]; NSLog(@"task2--end"); }); NSLog(@"--end--"); }];
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
|
[NSThread detachNewThreadWithBlock:^{ NSLog(@"--start--"); [self printCurrentThread]; dispatch_queue_t concurrentQueue = dispatch_queue_create("concurrentQueue", DISPATCH_QUEUE_CONCURRENT); dispatch_async(concurrentQueue, ^{ NSLog(@"task1--start"); [self printCurrentThread]; sleep(3); NSLog(@"task1--end"); }); dispatch_async(concurrentQueue, ^{ NSLog(@"task2--start"); [self printCurrentThread]; NSLog(@"task2--end"); }); NSLog(@"--end--"); }];
|
实验结果
在主线程向主队列同步派发,会造成死锁。
同步派发,会阻塞当前线程,该情况即阻塞主线程,然后等待任务返回;此时任务在主队列中,主队列中的任务需要等待主线程来执行;构成死锁。
在主线程向主队列异步派发,任务在主线程中按顺序执行。
在主线程向串行队列同步派发,任务在主线程中按顺序执行。
在主线程向串行队列异步派发,任务在同一个子线程里按顺序执行。
在主线程中派发任务,并不代表任务一定在主线程里执行。
在主线程向并发队列同步派发,任务在主线程里按顺序执行。
第 3、5 条,之所以会在主线程里执行,是因为 apple 进行了性能优化,切换线程是耗性能的。
在主线程向并发队列异步派发,任务在不同的子线程里同时执行。
在子线程向主队列同步派发,任务在主线程里按顺序执行。
在子线程向主队列异步派发,任务在主线程里按顺序执行。
在子线程向串行队列同步派发,任务在同一个子线程里按顺序执行。
在子线程向串行队列异步派发,任务在同一个子线程里按顺序执行,但是该子线程不是当前子线程。
在子线程向并发队列同步派发,任务在同一个子线程里按顺序执行。
在子线程向并发队列异步派发,任务在两个不同的子线程里同时执行,并且与当前子线程也不相同。
一些结论
- 主队列的任务都在主线程里执行
- 主线程里派发任务,不一定在主线程里执行(4 主线程里向串行队列异步派发,任务在子线程里执行)
- 同步派发的特征是塞当前线程,而不是让任务在当前线程立即执行(5 子线程向主队列同步派发,任务在主线程里执行)
- 串行队列异步派发,任务会在一个新子线程中执行(4 10 主线程/子线程向串行队列异步派发)
- 串行队列同步派发,任务会在当前线程中执行(3 9 主线程/子线程向串行队列同步派发)