面试题答案
一键面试1. NSLock
- 性能特点:
- 轻量级:NSLock是一种相对轻量级的锁,开销较小。它基于pthread_mutex实现。
- 简单直接:使用简单,调用lock方法加锁,unlock方法解锁。
- 适用场景:适用于较为简单的多线程同步场景,对性能要求不是特别苛刻,代码逻辑相对不复杂的情况。
- 性能优化:在锁竞争不激烈的情况下,NSLock能提供较好的性能。但如果竞争激烈,频繁的加锁解锁操作可能导致线程上下文切换频繁,影响性能。此时可以考虑优化代码结构,减少锁的持有时间。
2. @synchronized
- 性能特点:
- 便捷但开销大:语法简洁,使用方便,只需在需要同步的代码块前加上
@synchronized
关键字。它内部基于objc_sync,使用了引用计数来管理锁。 - 自动释放:不需要手动管理锁的释放,代码执行完同步块后自动解锁。
- 适用场景:适用于对代码简洁性要求高,对性能要求不是极致的场景,比如在少量数据同步,且代码结构相对简单的情况下。
- 便捷但开销大:语法简洁,使用方便,只需在需要同步的代码块前加上
- 性能优化:由于其内部实现较为复杂,在高并发场景下,性能不如一些更轻量级的锁。优化时尽量缩小同步块的范围,减少锁的持有时间,避免不必要的同步操作。
3. dispatch_semaphore
- 性能特点:
- 灵活高效:基于信号量机制,既可以实现锁的功能(信号量值设为1),也可以用于控制并发数。它是基于GCD(Grand Central Dispatch)的,性能较高。
- 适用于复杂场景:在处理复杂的多线程同步需求,如控制并发任务数量等场景下表现出色。
- 适用场景:适合在高并发场景下,对性能要求较高,且需要灵活控制并发的场景,例如网络请求并发数的控制。
- 性能优化:合理设置信号量的值可以有效提高性能。比如在控制并发数时,根据系统资源和任务特性设置合适的并发数,避免过多或过少的并发任务导致性能瓶颈。
4. 锁机制的选择
- 锁竞争程度:如果锁竞争不激烈,NSLock或@synchronized都可以满足需求,且@synchronized语法更简洁;若竞争激烈,dispatch_semaphore更具优势,因为它基于GCD,能更好地利用系统资源。
- 代码简洁性:如果追求代码简洁,对性能要求不是极其苛刻,@synchronized是不错的选择;若需要更精细的控制和更高性能,dispatch_semaphore更合适。
- 功能需求:若不仅需要同步,还需要控制并发数等复杂功能,dispatch_semaphore是唯一选择;而简单的同步场景,NSLock也能胜任。
5. 避免死锁问题
- 按序加锁:所有线程按照相同的顺序获取锁,例如总是先获取锁A,再获取锁B,避免循环依赖。
- 使用超时机制:在加锁时设置超时时间,若在规定时间内无法获取锁,则放弃并进行相应处理,避免线程无限等待。如使用dispatch_semaphore_wait函数时,可以设置超时参数。
- 死锁检测工具:利用Xcode自带的死锁检测工具,在开发和测试阶段及时发现潜在的死锁问题。如在Xcode中开启僵尸对象检测等相关功能,帮助定位死锁。
- 减少锁的嵌套:尽量减少锁的嵌套层数,降低死锁发生的可能性。如果无法避免,仔细分析嵌套顺序,确保一致性。