Comment on page
05 知识点梳理:多线程
比如在内存中维护一份数据,有多处地方可能会同时操作这块数据,怎么能保证数据安全? 这道题目总结得到要满足以下三点:
- 读写互斥
- 写写互斥
- 读读并发
@implementation KCPerson
- (instancetype)init
{
if (self = [super init]) {
_concurrentQueue = dispatch_queue_create("com.kc_person.syncQueue", DISPATCH_QUEUE_CONCURRENT);
_dic = [NSMutableDictionary dictionary];
}
return self;
}
- (void)kc_setSafeObject:(id)object forKey:(NSString *)key{
key = [key copy];
dispatch_barrier_async(_concurrentQueue, ^{
[_dic setObject:object key:key];
});
}
- (id)kc_safeObjectForKey::(NSString *)key{
__block NSString *temp;
dispatch_sync(_concurrentQueue, ^{
temp =[_dic objectForKey:key];
});
return temp;
}
@end
- 首先我们要维系一个GCD 队列,最好不用全局队列,毕竟大家都知道全局队列遇到栅栏函数是有坑点的,这里就不分析了!
- 因为考虑性能 死锁 堵塞的因素不考虑串行队列,用的是自定义的并发队列!
_concurrentQueue = dispatch_queue_create("com.kc_person.syncQueue", DISPATCH_QUEUE_CONCURRENT);
- 首先我们来看看读操作:
kc_safeObjectForKey
我们考虑到多线程影响是不能用异步函数的!说明:- 线程2 获取:
name
线程3 获取age
- 如果因为异步并发,导致混乱 本来读的是
name
结果读到了age
- 我们允许多个任务同时进去! 但是读操作需要同步返回,所以我们选择:
同步函数
(读读并发)
- 我们再来看看写操作,在写操作的时候对key进行了copy, 关于此处的解释,插入一段来自参考文献的引用:
函数调用者可以自由传递一个NSMutableString
的key
,并且能够在函数返回后修改它。因此我们必须对传入的字符串使用copy
操作以确保函数能够正确地工作。如果传入的字符串不是可变的(也就是正常的NSString
类型),调用copy
基本上是个空操作。
- 这里我们选择
dispatch_barrier_async
, 为什么是栅栏函数而不是异步函数或者同步函数,下面分析:- 栅栏函数任务:
- 之前所有的任务执行完毕,并且在它后面的任务开始之前,期间不会有其他的任务执行,这样比较好的促使 写操作一个接一个写
(写写互斥)
,不会乱!
- 为什么不是异步函数?
- 应该很容易分析,毕竟会产生混乱!
- 为什么不用同步函数?
- 如果读写都操作了,那么用同步函数,就有可能存在:我写需要等待读操作回来才能执行,显然这里是不合理!
**进程:**是资源分配的基本单位,它是程序执行时的一个实例,在程序运行时创建。
**线程:**是程序执行的最小单位,是进程的一个执行流,一个进程由多个线程组成。
多线程:
一个进程中并发执行多个线程,叫做多线程。在一个时间片内,CPU只能处理一个线程中的一个任务,对于一个单核CPU来说,在不同的时间片来执行不同线程中的任务,就形成了多个任务在同时执行的“假象”。
pthread
:- 即
POSIX Thread
,缩写称为pthread
,是线程的POSIX标准,是一套通用的多线程API,可以在Unix/Linux/Windows
等平台跨平台使用。iOS中基本不使用。
NSThread
:- 苹果封装的面向对象的线程类,可以直接操作线程,比起
GCD
,NSThread
效率更高,由程序员自行创建,当线程中的任务执行完毕后,线程会自动退出,程序员也可手动管理线程的生命周期。使用频率较低。
GCD
:- 全称
Grand Central Dispatch
,由C语言实现,是苹果为多核并行运算提出的解决方案,CGD会自动利用更多的CPU内核,自动管理线程的生命周期,程序员只需要告诉GCD需要执行的任务,无需编写任何管理线程的代码。GCD也是iOS使用频率最高的多线程技术。
NSOperation
:- 基 于GCD封装的面向对象的多线程技术,常配合NSOperationQueue使用,使用频率较高。
GCD
仅仅支持先进先出FIFO队列
,不支持异步操作之间的依赖关系设置。而NSOperation
中的队列可以被重新设置优先级,从而实现不同操作的执行顺序调整。NSOperation
支持KVO
,可以观察任务的执行状态。GCD
更接近底层,GCD
在追求性能的底层操作来说,是速度最快的。- 从异步操作之间的事务性,顺序行,依赖关系。
GCD
需要自己写更多的代码来实现,而NSOperation
已经内建了这些支持。 - 如果异步操作的过程需要更多的被交互和UI呈现出来,
NSOperation
更好。底层代码中,任务之间不太互相依赖,而需要更高的并发能力,GCD
则更有优势。
- 使用线程执行任务的时候,需要到线程池中去取线程进行任务分配。
- 首先判断线程池大小是否小于核心线程池大小,如果小于的话,创建新的线程执行任务;
- 如果当前线程池大小大于了核心线程池大小,然后开始判断工作队列是否已满,如果没满,将任务提交到工作队列。
- 如果工作队列已满,判断线程池的线程是否都在工作,如果有空闲线程没有在工作,就交给它去执行任务。