面试题答案
一键面试可能出现的具体问题
- 数据竞争:
- 多个线程同时访问和修改同一个对象的属性,而Objective - C的消息传递机制本身没有对这种情况进行自动同步。例如,一个线程通过
setter
方法修改对象的某个属性值,另一个线程同时通过getter
方法获取该属性值,可能导致获取到不一致的数据。 - 动态绑定过程中,若多个线程同时尝试解析一个方法的实现,可能会对方法缓存等数据结构产生竞争,导致缓存数据不一致。
- 多个线程同时访问和修改同一个对象的属性,而Objective - C的消息传递机制本身没有对这种情况进行自动同步。例如,一个线程通过
- 方法调用冲突:
- 当多个线程向同一个对象发送不同的消息时,可能会出现方法调用顺序混乱的情况。比如,一个线程调用对象的
start
方法开始某个任务,另一个线程同时调用stop
方法停止该任务,若处理不当,可能导致任务状态混乱。 - 动态绑定过程中,若一个方法正在被动态解析并替换实现,而此时多个线程同时调用该方法,可能导致调用到不一致的实现,甚至程序崩溃。
- 当多个线程向同一个对象发送不同的消息时,可能会出现方法调用顺序混乱的情况。比如,一个线程调用对象的
解决方案
- 使用锁机制:
- 互斥锁(Mutex):在访问共享对象的属性或调用可能产生竞争的方法时,使用互斥锁进行同步。例如:
@property (nonatomic, strong) NSLock *lock;
- (void)someMethod {
[self.lock lock];
// 访问或修改共享数据
[self.lock unlock];
}
- 读写锁(Read - Write Lock):如果对共享数据的操作读多写少,可以使用读写锁。读操作可以并发执行,写操作则需要独占锁。例如使用
pthread_rwlock
:
pthread_rwlock_t rwLock;
pthread_rwlock_init(&rwLock, NULL);
// 读操作
pthread_rwlock_rdlock(&rwLock);
// 执行读操作
pthread_rwlock_unlock(&rwLock);
// 写操作
pthread_rwlock_wrlock(&rwLock);
// 执行写操作
pthread_rwlock_unlock(&rwLock);
- GCD(Grand Central Dispatch):
- 串行队列(Serial Queue):将对共享对象的所有操作都放入一个串行队列中执行,这样可以保证操作的顺序性,避免竞争。例如:
dispatch_queue_t serialQueue = dispatch_queue_create("com.example.serialQueue", DISPATCH_QUEUE_SERIAL);
dispatch_async(serialQueue, ^{
// 访问或修改共享对象
});
- 同步函数(dispatch_sync):在需要确保某个操作完成后再继续执行其他操作时,可以使用同步函数。例如:
dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_sync(globalQueue, ^{
// 执行需要同步的操作
});
- 原子属性(Atomic Properties):将对象的属性声明为原子属性。例如:
@property (nonatomic, atomic, strong) id sharedObject;
原子属性会自动生成访问器方法的同步代码,保证在多线程环境下对属性的访问是线程安全的。
对系统性能和稳定性的影响
- 锁机制:
- 互斥锁:优点是实现简单,能有效避免数据竞争和方法调用冲突,提高系统稳定性。缺点是会引入锁的开销,包括加锁和解锁的时间,若锁的粒度较大,会降低系统并发性能,因为同一时间只有一个线程能访问共享资源。
- 读写锁:对于读多写少的场景,读写锁能提高系统并发性能,读操作可以并行执行。但对于写操作,仍然需要独占锁,可能会导致写操作的等待时间增加。在系统稳定性方面,读写锁可以有效避免数据竞争,但实现相对复杂,若使用不当可能会出现死锁等问题。
- GCD:
- 串行队列:能保证共享对象操作的顺序性,有效避免竞争,提高系统稳定性。但由于是串行执行,在多核环境下不能充分利用多核资源,可能会降低系统整体性能,特别是对于一些可以并行处理的任务。
- 同步函数:可以确保某些关键操作的顺序执行,提高系统稳定性。但同步函数会阻塞当前线程,直到指定队列中的任务完成,可能会影响系统的响应性能,尤其是在主线程中使用不当会导致界面卡顿。
- 原子属性:原子属性能保证属性访问的线程安全性,提高系统稳定性。但由于自动生成的同步代码,会增加属性访问的开销,相比非原子属性,性能会有所下降,特别是在频繁访问属性的情况下。