多线程的概念很多,其中还包含了嵌套使用,就像三角函数公式一样,巨多;但在代码的世界中,概念并不是泛泛的、抽象的,多敲敲代码就明白其中的奥义
本文仅使用GCD的几个基础API来从中体会这些概念
1.概念简介
在从代码中分析之前,还是要简单的描述一下,名词的基本概念,有个印象便可直接去代码中体会
- 进程线程
进程:一个在内存中运行的应用程序。如Windows系统中的.exe,iPhone上的在运行的某个APP
每个进程都有自己独立的一块内存空间,一个进程可以有多个线程,且至少有一个常驻线程,在iOS中这个必须常驻的唯一的线程叫做主线程。
线程: 进程要做事(任务)时,要把做的事交给线程去处理,线程负责当前进程中程序(要处理的任务)的执行,那段要执行的代码,也就是说要处理的事,叫任务
- 任务
任务: 交给线程做的事,是一行或者多行程序,在GCD中以block的形式存在
- 同步异步
能不能开启新的线程
同步:不具备开启线程的能力,在当前线程中执行;
同步添加任务到指定的队列中,在添加的任务执行结束之前,会一直等待,直到队列里面的任务完成之后再继续执行。
异步:具备开启线程的能力,在新开启的线程中执行
异步添加任务到指定的队列中,它不会做任何等待,可以继续执行任务
- 队列
任务的执行方式
并行:可以多个任务同时执行
串行:一个任务执行完毕,在执行下一个任务
2.多次调用体会
2.1:组合分析
区别\分析 | 并发队列 | 串行队列 | 主队列 |
---|---|---|---|
sync | 同步不能开启新的线程,所以尽管是并发队列,但同步添加任务到指定的队列中,在添加的任务执行结束之前,会一直等待,直到队列里面的任务完成之后再继续执行。任务的执行效果如:串行执行任务 | 同步不能开启新的线程,且串行队列,执行效果为:串行执行任务 | 在执行当前主线程任务的过程中,同步主队列到主线程上,因为都是主线程上的任务,添加的任务需要等当前任务执行完毕,当前任务需要等添加的任务执行完毕,所以锁死 |
async | 异步开启新线程,并发有多个线程支撑,任务执行效果:并发执行任务 | 异步可以开启多条线程,但因为是串行队列,一个任务执行完毕才执行下一个,所以开启一条新线程足矣,执行效果为:串行执行任务 | 当前任务和添加到主队列中的任务都在主线中执行,但是异步添加任务到指定的队列中,它不会做任何等待,可以继续执行任务,所以会先执行完当前任务再执行添加的任务 |
区别\结论 | 并发队列 | 串行队列 | 主队列 |
---|---|---|---|
sync | 未开启新的线程,串行执行任务 | 未开启新的线程,串行执行任务 | 死锁 |
async | 开启多条新线程,并发执行任务 | 开启一条新线程:串行执行任务 | 没有开启新线程,串行执行任务 |
2.2:代码体会
一下的打印皆按照顺序打印多次XXXX
2.2.1:同步串行
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(@"%@", [NSThread currentThread]);
NSLog(@"KAISHI");
dispatch_queue_t queue = dispatch_queue_create("HD", nil);
for (int x = 0; x < 10; x++) {
dispatch_sync(queue, ^{
[NSThread sleepForTimeInterval:2];
NSLog(@"%d -- %@", x, [NSThread currentThread]);
});
}
NSLog(@"JIESHU");
}
输出结果:
2022-07-27 13:55:14.740593+0800 Test[7227:347198] <_NSMainThread: 0x600001414040>{number = 1, name = main}
2022-07-27 13:55:14.740823+0800 Test[7227:347198] KAISHI
2022-07-27 13:55:16.741187+0800 Test[7227:347198] 0 – <_NSMainThread: 0x600001414040>{number = 1, name = main}
2022-07-27 13:55:18.742611+0800 Test[7227:347198] 1 – <_NSMainThread: 0x600001414040>{number = 1, name = main}
2022-07-27 13:55:20.744061+0800 Test[7227:347198] 2 – <_NSMainThread: 0x600001414040>{number = 1, name = main}
2022-07-27 13:55:22.745448+0800 Test[7227:347198] 3 – <_NSMainThread: 0x600001414040>{number = 1, name = main}
2022-07-27 13:55:24.745874+0800 Test[7227:347198] 4 – <_NSMainThread: 0x600001414040>{number = 1, name = main}
2022-07-27 13:55:26.747351+0800 Test[7227:347198] 5 – <_NSMainThread: 0x600001414040>{number = 1, name = main}
2022-07-27 13:55:28.748105+0800 Test[7227:347198] 6 – <_NSMainThread: 0x600001414040>{number = 1, name = main}
2022-07-27 13:55:30.749498+0800 Test[7227:347198] 7 – <_NSMainThread: 0x600001414040>{number = 1, name = main}
2022-07-27 13:55:32.750432+0800 Test[7227:347198] 8 – <_NSMainThread: 0x600001414040>{number = 1, name = main}
2022-07-27 13:55:34.751921+0800 Test[7227:347198] 9 – <_NSMainThread: 0x600001414040>{number = 1, name = main}
2022-07-27 13:55:34.752264+0800 Test[7227:347198] JIESHU
分析:
- 代码是放在ViewDidLoad中的,所以
[NSThread currentThread]
是{number = 1, name = main}为主线程重执行任务; - sync不开启新的线程,queue是serial为串行队列,需要执行完一个任务再执行一个任务,所以打印时间都相差睡眠的2秒
JIESHU
在10组同步串行任务之后打印
2.2.2 :同步并行
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(@"%@", [NSThread currentThread]);
NSLog(@"KAISHI");
dispatch_queue_t queue = dispatch_queue_create("HD", DISPATCH_QUEUE_CONCURRENT);
for (int x = 0; x < 10; x++) {
dispatch_sync(queue, ^{
[NSThread sleepForTimeInterval:2];
NSLog(@"%d -- %@", x, [NSThread currentThread]);
});
}
NSLog(@"JIESHU");
}
打印结果
2022-07-27 14:52:49.304526+0800 Test[7688:381587] <_NSMainThread: 0x600001e9c9c0>{number = 1, name = main}
2022-07-27 14:52:49.304746+0800 Test[7688:381587] KAISHI
2022-07-27 14:52:51.306111+0800 Test[7688:381587] 0 – <_NSMainThread: 0x600001e9c9c0>{number = 1, name = main}
2022-07-27 14:52:53.307739+0800 Test[7688:381587] 1 – <_NSMainThread: 0x600001e9c9c0>{number = 1, name = main}
2022-07-27 14:52:55.309328+0800 Test[7688:381587] 2 – <_NSMainThread: 0x600001e9c9c0>{number = 1, name = main}
2022-07-27 14:52:57.310813+0800 Test[7688:381587] 3 – <_NSMainThread: 0x600001e9c9c0>{number = 1, name = main}
2022-07-27 14:52:59.311261+0800 Test[7688:381587] 4 – <_NSMainThread: 0x600001e9c9c0>{number = 1, name = main}
2022-07-27 14:53:01.312800+0800 Test[7688:381587] 5 – <_NSMainThread: 0x600001e9c9c0>{number = 1, name = main}
2022-07-27 14:53:03.314424+0800 Test[7688:381587] 6 – <_NSMainThread: 0x600001e9c9c0>{number = 1, name =