版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
iOS多线程高频面试题及详细答案(实战版)一、基础认知类(入门必问)1、iOS中多线程的实现方案有哪些?各自的优缺点?iOS主流多线程方案分为四种:pthread、NSThread、GCD、NSOperation,日常开发99%场景只用GCD和NSOperation。1.pthread基于C语言的跨平台线程方案,底层纯C函数。优点:跨平台、轻量。缺点:手动管理线程生命周期(创建、销毁、休眠),代码繁琐,极易内存泄漏,开发中几乎不用,仅做底层了解。2.NSThread面向对象封装的pthread,OC原生线程类。优点:使用简单,可直接获取线程对象、手动控制线程启停。缺点:需要手动管理线程生命周期,线程数量不可控,容易创建大量子线程造成性能损耗,不适合大量任务并发场景。3.GCD(GrandCentralDispatch)系统级的线程管理方案,纯C语言封装,自动管理线程生命周期。优点:自动线程复用、性能极高、代码简洁、支持队列调度、延迟执行、栅栏、组任务等高级功能,适配绝大多数开发场景。缺点:复杂任务依赖、任务取消场景不如NSOperation灵活。4.NSOperation+NSOperationQueue基于GCD上层的OC封装,面向对象操作任务。优点:支持任务暂停、取消、重启、任务依赖、最大并发数控制,适合批量网络请求、批量下载等复杂任务场景。缺点:相比GCD代码稍繁琐,轻量任务使用略显冗余。2、GCD的队列和线程的关系?主队列、全局队列、自定义队列区别?核心结论:GCD是队列调度任务,系统自动分配线程执行任务,队列不对应固定线程。队列只负责存放任务,线程负责执行任务。1.主队列(mainqueue)系统唯一的串行队列,绑定主线程,所有UI刷新、主线程任务必须在主队列执行。主队列任务遵循FIFO顺序执行,且不会开辟新线程。2.全局队列(globalqueue)系统提供的并发队列,无数量限制,自动开辟、复用子线程。分四个优先级:高、默认、低、后台。日常开发默认使用默认优先级即可,禁止随意使用高优先级避免抢占系统资源。3.自定义队列分为自定义串行队列、自定义并发队列。自定义串行队列:每次只执行一个任务,线程可复用,适合处理有序、互斥任务(读写操作、数据缓存)。自定义并发队列:可同时执行多个任务,线程由系统自动调度。3、串行队列和并发队列的核心区别?串行队列:任务按添加顺序依次执行,前一个任务结束后才会执行下一个,同一时刻只有一个任务在执行,不管是同步还是异步派发,任务执行有序。并发队列:任务可以同时执行,系统会自动开启多个线程并行处理任务,任务执行顺序不受添加顺序约束。关键误区:队列类型决定任务执行规则,派发方式(同步/异步)决定是否开启新线程。二、GCD核心难点(面试高频)1、GCD同步sync、异步async的区别?async异步派发:立即返回,不阻塞当前线程,系统开辟子线程执行任务(主队列除外)。sync同步派发:阻塞当前线程,等待队列中任务执行完成后才返回,不会开辟新线程。四大组合场景核心结论(面试必考):主队列+sync:死锁(主线程等待任务执行,任务等待主线程空闲,互相阻塞)主队列+async:不阻塞,任务切到主线程延后执行,日常刷新UI常用子线程串行/并发队列+sync:阻塞当前子线程,任务串行执行子线程队列+async:不阻塞,正常多线程执行2、什么是GCD死锁?常见死锁场景和解决方案?死锁本质:多个线程互相等待对方释放资源,或者同一线程自身等待未完成的任务,导致线程永久阻塞。常见场景1:主线程同步执行主队列任务dispatch_sync(dispatch_get_main_queue(),^{});原因:当前主线程正在运行,sync要求等待队列任务完成,而主队列任务需要主线程空闲才能执行,互相等待触发死锁。常见场景2:同一串行队列嵌套sync派发任务外层串行队列任务中,同步派发任务到当前同一个串行队列。外层任务占用队列,等待内层任务完成;内层任务排队无法执行,触发死锁。解决方案1、主线程刷新UI一律用async,禁止sync;2、串行队列内部嵌套任务,使用async派发,不要用sync;3、耗时同步操作尽量放在子线程,避免阻塞主线程。3、GCD栅栏函数barrier的作用?使用场景?栅栏函数分dispatch_barrier_async和dispatch_barrier_sync。核心作用:拦截队列前后任务,保证栅栏任务执行时,前面所有任务已完成,后面所有任务等待栅栏任务完成后再执行。注意:栅栏函数仅对自定义并发队列生效,对全局队列、主队列无效。经典使用场景:多读单写数据读取操作频繁、写入操作较少的场景(本地缓存、模型数据读写)。读任务用普通async并发执行,提升读取效率;写任务用barrier栅栏,保证写入时无读写冲突,数据安全。4、GCD延时函数dispatch_after的底层原理?有什么坑?底层原理:dispatch_after不是定时触发任务,是等待指定时间后,将任务追加到目标队列,并非精准计时执行。常见坑点1、时间不精准:如果队列任务堆积,延时任务会排队延迟执行;2、不会主动取消:页面销毁后,延时任务依然会执行,容易造成野指针、界面刷新崩溃;3、依赖队列状态:派发的队列如果被释放,会直接崩溃。解决方案:页面退出时手动标记取消,或使用NSTimer、NSOperation替代(支持主动取消)。5、GCD队列组dispatch_group的作用?常用场景?队列组用于监听多个异步任务全部执行完成,统一回调结果,解决多异步任务同步收尾的问题。核心API:group_enter、group_leave、group_notify、group_wait使用规范:enter和leave必须成对出现,否则会导致notify不回调、线程卡死。实战场景1、多个并行网络请求,全部成功后刷新界面;2、多文件并发下载/解压,全部完成后统一回调;3、批量数据异步处理,统一收尾统计。区别:group_wait会阻塞当前线程,尽量少用;优先用group_notify异步回调,不卡顿界面。三、NSOperation专项面试题1、NSOperation和GCD的对比?为什么有了GCD还要用NSOperation?GCD是底层C语言API,侧重任务调度,轻量高效;NSOperation是GCD的上层OC封装,侧重任务管理。NSOperation独有优势,是GCD无法替代的:1、支持任务暂停、继续、取消,适合长耗时任务(视频导出、文件下载);2、支持任务依赖,可精准控制多个任务执行顺序(A任务执行完再执行B);3、可设置最大并发数,精准控制同时执行的任务数量,避免线程爆炸;4、支持KVO监听任务状态(isExecuting、isFinished、isCancelled)。适用场景:简单异步任务用GCD,复杂、可中断、有依赖的批量任务用NSOperation。2、NSOperation的任务状态流转?自定义NSOperation注意点?核心状态:isReady->isExecuting->isFinished/isCancelled所有状态变更必须手动触发KVO,否则队列无法识别任务状态,会导致队列异常。自定义NSOperation核心注意点1、必须重写main方法,编写任务核心逻辑;2、手动管理executing、finished状态,保证KVO触发;3、任务执行中实时判断isCancelled,取消后立即终止任务,避免无效执行;4、杜绝任务内部嵌套复杂死循环,防止任务无法结束。四、线程安全与性能优化(进阶必考)1、iOS多线程常见的线程安全问题?产生原因?核心问题:多条线程同时读写同一资源(全局变量、单例、缓存数据),导致数据错乱、脏数据、崩溃。常见场景:1、子线程并发修改同一数组/字典,导致数组越界、野指针崩溃;2、单例未加锁,多线程同时初始化,创建多个实例;3、异步读写缓存数据,数据覆盖、丢失。2、iOS常用的锁机制有哪些?优缺点对比?1.@synchronized优点:使用最简单,一行代码加锁,自动解锁,不易出错。缺点:性能最差,底层包含多次对象校验、缓存查询,高并发场景耗时明显。2.pthread_mutex_t互斥锁优点:性能极高,底层原生C锁,适合高频读写场景。缺点:需要手动初始化、销毁锁,代码繁琐,需注意避免死锁。3.NSLock/NSRecursiveLockNSLock基础互斥锁,性能优于@synchronized;NSRecursiveLock递归锁,支持同一线程重复加锁,解决递归任务加锁死锁问题。4.自旋锁OSSpinLock线程等待时不休眠,空循环等待,性能极高。但iOS10之后废弃,存在优先级反转安全问题,禁止使用。实战选型普通简单场景:用@synchronized;高频并发读写:用pthread_mutex_t;递归加锁场景:用NSRecursiveLock。3、单例的线程安全写法?为什么要这么写?日常最标准、安全、高性能的单例写法:GCD一次性代码+(instancetype)shareInstance{staticDemo*instance=nil;staticdispatch_once_tonceToken;dispatch_once(&onceToken,^{instance=[[selfalloc]init];});returninstance;}原理:dispatch_once底层自带线程锁,保证多线程环境下代码仅执行一次,无需手动加锁,性能最优,绝对线程安全。淘汰写法:手动判断if(instance==nil)初始化,多线程并发时会创建多个实例,非线程安全。4、什么是线程爆炸?如何避免?线程爆炸:短时间内创建大量子线程,系统频繁调度线程、切换上下文,消耗大量CPU资源,导致页面卡顿、APP耗电激增、甚至闪退。产生原因:循环中大量异步派发任务,无并发限制,系统无限开辟新线程。解决方案1、批量任务优先使用NSOperationQueue,设置maxConcurrentOperationCount限制最大并发数;2、大量异步任务改用自定义串行/有限并发队列,控制线程数量;3、避免嵌套异步任务,减少无效线程创建。五、面试经典错题/笔试题解析1、主线程中执行async到主队列,会不会死锁?为什么?不会死锁。async是异步派发,不会阻塞当前主线程。任务会追加到主队列尾部,当前主线程代码执行完毕后,再执行队列中的异步任务。只有sync同步阻塞主队列才会死锁。2、子线程串行队列嵌套sync自己队列,会不会死锁?会死锁。当前串行队列正在执行外层任务,sync同步派发内层任务到同一队列,内层任务排队等待;而sync会阻塞外层任务,等待内层任务完成,双向等待触发死锁。3、GCD全局队列能否用栅栏函数?为什么?不可以。全局队列是系统公共队列,整个APP所有业务都在复用,栅栏函数会拦截队列所有任务,会阻塞全局所有异步任务,造成全局卡顿,系统直接屏蔽该功能,栅栏失效。日常栅栏仅用于自定义并发队列。4、为什么UI刷新必须在主线程?UIKit所有组件非线程安全,底层UI渲染、图层操作、视图层级操作都依赖主线程RunLoop驱动。如果在子线程刷新UI,多条线程同时操作同一UI对象,会造成UI状态错乱、图层渲染异常、隐性崩溃、界面闪烁等问题。系统规定所有UI操作必须在主线程执行。六、实战场景问答(面试官追问高频)1、网络请求为什么要放在子线程?回调为什么切回主线程?网络请求属于耗时IO操作,放在主线程会阻塞主线程RunLoop,导致页面卡顿、滑动不流畅、出现卡死现
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2026年河南省新郑市高一化学上册期末考试模拟测试卷附参考答案【满分必刷】
- 2026年江苏省溧阳市高三生物上册期末考试模拟检测卷及参考答案
- 2026年山西省汾阳市高一化学上册期末考试模拟检测卷【A卷】附答案
- 2026年广东省吴川市高三生物上册期末考试试卷带答案
- 2026年江苏省张家港市高一化学上册期末考试真题附答案(预热题)
- 2026年山东省荣成市高一化学上册期末考试试卷附参考答案(精练)
- 基于柔性导向机构的压电超声显微切割仪:设计创新与实验验证
- 基于机理与数据混合驱动的高炉分布式炉温建模方法:精准预测与优化控制
- 基于机器视觉的前方车辆检测技术:原理、应用与挑战
- 基于机会理论的海上风电机组维修策略模型构建与优化研究
- 雨课堂学堂在线学堂云《运动损伤预防与康复(北体)》单元测试考核答案
- 2025年10月自考13683管理学原理中级试题及答案
- 《理解媒介:论人的延伸》阅读札记
- 2025年大学《缅甸语》专业题库- 缅甸语口译实践与案例分析
- 蔗渣锅炉培训课件教学
- 安格斯MAX市场计划
- 子宫宫腔常见病变
- 长江存储培训课件
- 非标设备项目管理制度
- 《热学(第二版)》杨体强编-李椿 第9章 相变学习资料
- 梦想启航励志前行主题班会课件
评论
0/150
提交评论