多线程
- 多线程的应用 主要用于耗时的操作
(1) 耗时操作,例如网络图片、视频、歌曲、书籍等资源下载
(2) 游戏中的声音播放
- 多线程基本概念
(1) 每一个程序都有一个主线程,程序启动时创建(调用main来启动)
(2) 主线程的生命周期是和应用程序绑定的,程序退出(结束)时,主线程也就停止了
(3) 多线程技术表示,一个应用程序有多个线程,使用多线程能提供CPU的使用率,防止主线程堵塞
(4) 任何有可能堵塞主线程的任务不要在主线程执行(访问网络)
- 程序是计算机指令的集合,它以文件的形式存储在磁盘上。
- 每一个进程启动之后,会有一个主线程,遇到耗时的操作时,新建线程去执行可以保证主线程的流畅,新建线程本身会消耗系统资源 线程之间要控制执行顺序相对比较复杂。
进程与线程概念
(1) 进程:是一个程序在其自身的地址空间中的一次执行活动。
- 进程是资源申请、调度和独立运行的单位,因此,它使用系统中的运行资源;
- 而程序不能申请系统资源,不能被系统调度,也不能作为独立运行的单位,因此,它不占用系统的运行资源。
(2) 线程:是进程中的一个单一的连续控制流程。一个进程可以拥有多个线程。
- 线程又称为轻量级进程,它和进程一样拥有独立的执行控制,由操作系统负责调度,区别在于线程没有独立的存储空间,而是和所属进程中的其它线程共享一个存储空间,这使得线程间的通信远较进程简单。
(3) 一个运行的程序就是一个进程或者叫做一个任务
(4) 一个进程至少包含一个线程,线程是程序的执行流
(5) iOS程序启动时,在创建一个进程的同时, 会开始运行一个线程,该线程被称为主线程
(6) 主线程是其他线程最终的父线程,所有界面的显示操作必须在主线程进行!!!
(7) 后台线程无法更新UI界面和响应用户点击事件
(8) 系统中的每一个进程都有自己独立的虚拟内存空间,而同一个进程中的多个线程则共用进程的内存空间
(9) 每创建一个新的线程,都会消耗一定内存和CPU时间
(10) 当多个线程对同一个资源出现争夺的时候需要注意线程安全问题
- 多线程的优势与难点
- 优势
- 充分发挥多核处理器优势,将不同线程任务分配给不同的处理器,真正进入“并行运算”状态
- 将耗时、轮询或者并发需求高等任务分配到其他线程执行,并由主线程负责统一更新界面会使得应用程序更加流畅,用户体验更好
- 当硬件处理器的数量增加,程序会运行更快,而无需做任何调整
- NSThread 每个NSThread对象对应一个线程,量级较轻
- NSOperation/NSOperationQueue 面向对象的线程技术
- GCD —— Grand Central Dispatch 是基于C语言的框架,可以充分利用多核,是苹果推荐使用的多线程技术
- 以上这三种编程方式从上到下,抽象度层次是从低到高的,抽象度越高的使用越简单,也是Apple最推荐使用的。但是就目前而言,iOS的开发者,需要了解三种多线程技术的基本使用过程。因为很多框架技术分别使用了不同多线程技术。
- 三种多线程技术的对比
iOS的三种多线程技术
(1) NSThread:
- 优点:NSThread 比其他两个轻量级,使用简单
- 缺点:不能控制线程的执行顺序(需要自己管理线程的生命周期、线程同步、加锁、睡眠以及唤醒等。线程同步对数据的加锁会有一定的系统开销)(需要使用start方法,才能启动实例化出来的线程、控制并发线程数、先后顺序困难,例如:下载图片(后台线程) -> 滤镜美化(后台线程) -> 更新UI(主线程))
(2) NSOperation:
- 不需要关心线程管理,数据同步的事情,可以把精力放在自己需要执行的操作上
- NSOperation是面向对象的
(3) GCD:
- Grand Central Dispatch是由苹果开发的一个多核编程的解决方案。iOS4.0+才能使用,是替代NSThread
- NSOperation的高效和强大的技术
- GCD是基于C语言的
- 谁的编号为一,谁就是主线程;[NSThread currentThread] = {number = 1, name = main}
- 非主线程,跳到主线程,(根类方法)
- - (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait;
- NSObject多线程方法
(1) [NSThread currentThread] 可以返回当前运行的线程
- num = 1 说明是主线程
- 在任何多线程技术中(NSThread,NSOperation,GCD),均可以使用此方法,查看当前的线程情况。
(2) 新建后台线程,调度任务 对NSThread线程封装
- [self performSelectorInBackground:@selector(bigTask) withObject:nil]
- 使用performSelectorInBackground是可以修改UI的,but强烈不建议如此使用。
(3) 更新界面
- 使用performSelectorOnMainThread可以返回主线程上执行任务。
- 提示:NSObject对象均可以调用此方法。
(4) 内存管理
线程任务要包在@autoreleasepool(自动释放池)中,否则容易引起内存泄露,而且非常难发现。
- NSObject的多线程小结
(1) 开启后台执行任务的方法
- (void)performSelectorInBackground:(SEL)aSelector withObject:(id)arg
(2) 在后台线程中通知主线程执行任务的方法
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait;
(3) 获取线程信息
- [NSThread currentThread];
(4) 线程休眠(仅适用于开发调试时使用)
- [NSThread sleepForTimeInterval:1.0f]