首先了解单线程:
一、单线程的应用,整个应用中只有一个顺序执行流,
当执行流在执行某个耗时的操作,或者不能立即完成的任务时(比如网络通信、复杂的运行)该执行流就会被阻塞,整个应用就会卡在那里无法继续执行,因此单线程的程序功能往往是非常有限的.
我们可以这样理解,单线程程序如同只雇佣一个服务员的餐厅,他必须做完一件事情后才能做下一件的事情,多线程程序则如同雇用多个服务员的餐厅,他们可以同时进行多件事情。
二、线程和进程
所有运行中的任务通常对应一个进程Process (prəʊsɛsˈ),当一个程序进入内存运行后即变成了一个进程,进程是系统进行资源分配和调度的一个独立单位.当一个进程运行时,内部可能包含多个顺序执行流,每个顺序执行流就是一个线程.
一般而言进程包括如下三个特征:
1、独立性:进程是系统中的独立存在的实体,有自己独立的资源,每一个进程都有自己的私有地址空间,没有允许,其它用户进程不可以直接访问其它的进程空间。
2、动态性:进程与程序的区别在于,程序只是一个静态的指令集合,而进程是一个正在系统中活动的指令集合,在进程中加入了时间的概念,进程具有自己的生命周期和各种不同的状态,这些概念在程序中都是不具备的。
3、并发性:多个进程可以在单个处理器上并发执行。
4、并发性(concurrency kənˈkʌr(ə)ns)和 并行性(parallel ˈparəlɛl ) 是两个概念,
4.1、并发性:指在同一时刻只能有一条指令执行,但多个进程指定被快速轮换执行,使得在宏观上具有多个进程同时执行的效果。大部分操作系统都支持多线程并发运行,例如:一边写程序一边查看手册同时播放音乐等等……这些进程看上去像是在同时工作。对于一个CPU,它在某个时间点上只能执行一个程序,只能运行一个进程,CPU不断的在这些进程之间轮换执行,
4.2、并行性:指在同一时刻有多少指令在多个处理器上同时执行。
三、多线程和多进程
多线程则扩展了多进程的概念,使得同一个进程可以同时并发处理多个任务,
线程(Thread θrɛd )也被称作轻量级进程(Lightweight Process)
线程是进程的执行单元,线程在程序中是独立的、并发的执行流。
当进程被初始化后,主线程就被创建了,对于绝大多数的应用程序来说,通常仅要求有一个主线程,但我们可以在该程序内创建多条顺序执行流,这些顺序执行流就是线程 每条线程也是相互独立的。
操作系统可以同时执行多个任务,每个任务就是进程;进程可以同时执行多个任务,每个任务就是线程。一个程序运行后至少有一个进程,一个进程里可以有多个线程,但至少要包含一个线程。也就是说一个线程必须有一个父进程,线程是进程的组成部分,
线程可以拥有自己的堆栈,自己的程序计数器和自己的局部变量,但不再拥有系统资源。线程是独立运行的,线程的执行是抢占式的。也就是说当前运行的线程在任何时候都可能被挂起,以方便另外一个线程可以运行。一个线程可以创建和撤销另一个线程,线程的调度和管理有进程本身负责完成。
四、多线程
1、为什么要用多线程?
答: 每个iOS 应用程序都有专门的自己的用来更新显示UI界面或处理用户的触摸事件的-主线程,因此不能将其他太耗时的操作放在主线程中去执行,不然会造成主线程堵塞(出现卡机的现象),带来极坏的用户体验。
So 一般的解决方案就是将那些耗时的操作放到另外一个线程中去执行,
So 多线程编程是防止主线程堵塞,增加运行效率等等的最佳方法。而原始的多线程方法存在很多的毛病,包括线程锁死等。
例如: 用户上的某个按钮,该按钮需要执行的任务需要几秒甚至几十秒,如果直接在UI线程中完成这个任务,这个任务执行完成、返回之前,UI线程被该任务阻塞,无法响应用户的其他操作--在这个时间内,用户的iOS操作系统的操作将不会有任何反应(除非用户单击home键返回)这不是用户希望的结果,最好的做法是:将任何耗时的任务,(比如复杂的运算、从网络下载数据等操作)都放在非UI线程中完成,这样UI线程就不会被阻塞,IOS应用也不会失去响应。
2、多线程是什么?
答: 多线程是个复杂的概念,按字面意思是同步完成多项任务,提高了资源的使用效率,
1>从硬件、操作系统、应用软件不同的角度去看,多线程被赋予不同的内涵,对于硬件,现在市面上多数的CPU都是多核的,多核的CPU运算多线程更为出色;
2>从操作系统角度,是多任务,现在用的主流操作系统都是多任务的,可以一边听歌、一边写博客;
对于应用来说,多线程可以让应用有更快的回应,可以在网络下载时,同时响应用户的触摸操作。
3>在iOS应用中,对多线程最初的理解,就是并发,它的含义是原来先做烧水,再摘菜,再炒菜的工作,会变成烧水的同时去摘菜,最后去炒菜。
3、 多线程的底层实现?
1> 首先搞清楚什么是线程、什么是多线程?
2> Mach是第一个以多线程方式处理任务的系统,因此多线程的底层实现机制是基于Mach的线程
3> 开发中很少用Mach级的线程,因为Mach级的线程没有提供多线程的基本特征,线程之间是独立的
4> 开发中实现多线程的方案
4.1 C语言的POSIX接口:#include <pthread.h>
4.2 OC的NSThread
4.3 C语言的GCD接口(性能最好,代码更精简)
4.4 OC的NSOperation和NSOperationQueue(基于GCD)
五、iOS中有哪些多线程编程?
iOS中的多线程,是Cocoa框架下的多线程,通过Cocoa的封装,可以让我们更为方便的使用线程,做过C++的同学可能会对线程有更多的理解,比如线程的创立,信号量、共享变量有认识,Cocoa框架下会方便很多,它对线程做了封装,有些封装,可以让我们创建的对象,本身便拥有线程,也就是线程的对象化抽象,从而减少我们的工程,提供程序的健壮性。
iOS支持-多个-层次的-多线程编程,提供了如下三种多线程编程的技术:
1.NSThread 每个 NSThread对象 对应一个线程,量级较轻(真正的多线程)
2.以下两点是苹果专门开发的“并发”技术,使得程序员可以不再去关心线程的具体使用问题
1> NSOperation/NSOperationQueue 面向对象的线程技术
2> GCD —— Grand Central Dispatch(派发) 是基于C语言的框架,可以充分利用多核,是苹果推荐使用的多线程技术
//使用NSThread实现多线程,(θrɛd )
//使用NSOperation与 NSOperationQueue 实现多线程
//使用GCD实现多线程(Grand Central Dispatch)
以上这三种编程方式从上到下,抽象度层次是从低到高的,抽象度越高的使用越简单,也是Apple最推荐使用的,在项目中很多框架技术分别使用了不同多线程技术。
六、三种多线程技术的对比
- NSThread:
–优点:NSThread比其他两种多线程方案较轻量级,更直观地控制线程对象(θred )
–缺点:需要自己管理线程的生命周期、线程同步、加锁、睡眠以及唤醒等。线程同步对数据的加锁会导致一定的性能开销
2.NSOperation:
–NSOperation是面向对象的 (Cocoa Operations 是基于OC实现的)
NSOperation 是以-面向对象-的方式-封装了-需要执行的操作,–不需要关心线程管理,数据同步的事情,可以把精力放在自己需要执行的操作上
NSOperation是一个抽象基类,iOS提供了两种默认实现:
NSInvocationOperation (ɪnvəˈkeɪʃn) 和 NSBlockOperation,当然也可以自定义NSOperation
3.GCD:
-Grand Central Dispatch (grænd sentrəl dɪˈspætʃ 简称GCD,iOS4.0+才能使用,基于C语言的)
–GCD是由苹果开发的一个多核编程的解决方案。是替代NSThread, NSOperation的高效和强大的技术 提供了一些新特性、运行库来支持多核并行编程-,它的关注点更高:如何在多个cpu上提升效率
GCD从系统级别提供的一个易用的多线程类库,具有运行时的特点,能充分利用多核心硬件。
GCD的API接口为C语言的函数,函数参数中多数有Block,关于Block的使用为我们提供强大的“接口”
七、一般的面试问题:
- 线程间怎么通信?
1> performSelector:onThread:withObject:waitUntilDone:
2> NSMachPort
- 网络图片处理问题中怎么解决一个相同的网络地址重复请求的问题?
利用字典(图片地址为key,下载操作为value)
- 谈谈多线程安全的几种解决办法及多线程安全怎么控制?
1> 只在主线程刷新访问UI
2> 如果要防止资源抢夺,得用@synchronized [ˈsɪŋkrəˌnaɪzd]进行加锁保护
3> 如果异步操作要保证线程安全等问题,尽量使用GCD(有些函数默认就是安全的) 《你可以看一下之前的文章单例的创建,采用GCD的方式创建的》- 你用过NSOperationQueue么?为什么要使用NSOperationQueue,实现了什么? 以及描述它和GCD的区别和类似的地方?(提示:可以从两者的实现机制和适用范围来描述)。
1> GCD是纯C语言的API,NSOperationQueue是基于GCD的OC版本封装
2> GCD只支持FIFO的队列,NSOperationQueue可以很方便地调整执行顺序、设置最大并发数量
3> NSOperationQueue可以在轻松在Operation间设置依赖关系,而GCD需要写很多的代码才能实现
4> NSOperationQueue支持KVO,可以监测operation是否正在执行(isExecuted)、是否结束(isFinished),是否取消(isCanceld)
5> GCD的执行速度比NSOperationQueue快
任务之间不太互相依赖使用:GCD
任务之间有依赖\或者要监听任务的执行情况使用:NSOperationQueue
- 在使用GCD以及block时要注意些什么?它们两是一回事儿么?block在ARC中和传统的MRC中的行为和用法有没有什么区别,需要注意些什么?
Block的使用注意:
1> block的内存管理
2> 防止循环retian
λ 非ARC(MRC):__block
λ ARC:__weak__unsafe_unretained
使用block是要注意,若将block做函数参数时,需要把它放到最后,GCD是Grand Central Dispatch,是一个对线程开源类库,而Block是闭包,是能够读取其他函数内部变量的函数。
6.在异步线程中下载很多图片,如果失败了,该如何处理?请结合RunLoop来谈谈解决方案.(提示:在异步线程中启动一个RunLoop重新发送网络请求,下载图片)
1> 重新下载图片
2> 下载完毕, 利用RunLoop的输入源回到主线程刷新UIImageVIUew
7.在项目什么时候选择使用GCD,什么时候选择NSOperation?
使用NSOperationQueue用来管理子类化的NSOperation对象,控制其线程并发数目。GCD和NSOperation都可以实现对线程的管理,区别是 NSOperation和NSOperationQueue是多线程的面向对象抽象。
项目中使用NSOperation的优点是: NSOperation是对线程的高度抽象,在项目中使用它,会使项目的程序结构更好,子类化NSOperation的设计思路,是具有面向对象的优点(复用、封装),使得实现是多线程支持,而接口简单,建议在复杂项目中使用。
项目中使用GCD的优点是GCD本身非常简单、易用,对于不复杂的多线程操作,会节省代码量,而Block参数的使用,会是代码更为易读,建议在简单项目中使用
8、您是否做过异步的网络处理和通讯方面的工作?如果有,能具体介绍一些实现策略么?
使用NSOperation发送异步网络请求,使用NSOperationQueue管理线程数目及优先级,底层是用NSURLSession
9、OC中有线程池(线程队例)吗?NSOperationQueue是如何管理线程的:
1>、NSPOperationQueue是OC中的线程池,线程可以存放多个线程
2>、NSPOperationQueue可以管理线程的并发数,还可以管理线程之间的优先级。