问题演示: 在执行好事操作的时候,UI无法执行! (滚动/点击)---- 主线程!
进程和线程有什么区别?
进程:在系统中,"正在运行"的应用程序! -- "进程"为应用程序分配独立的"内存"空间!
1.app启动!
线程:线程"执行进程中的代码"!---- 线程是CPU调度的最小单元!
2.app中的代码被执行!
一个应用程序启动之后,会默认生成一条线程----> "主线程"
一个线程中有可能有很多代码(有很多代码块/方法)!------->线程中代码的执行顺序?
在同一条线程中,任务(代码)是按顺序执行的!线程只能执行完一块代码再执行另外一块代码! ------ "串行执行"
耗时操作---->统统放在"子线程"中执行!
子线程: "主线程"之外的线程都叫做子线程! 自己创建的线程都是子线程!
线程:对象!
开启线程之后,为什么"不同线程"之间的任务就可以"同时执行"!
多线程的原理:线程是由CPU执行!CPU快速地在多条线程之间切换(调度/执行)!CPU执行线程的速度非常快!给我们造成一种多条线程"同时"执行的'假象';
多条线程之间任务'同时执行' -----> "并发执行"
任务是没有顺序的,同时执行!
多核CPU同时执行线程:----> "并行执行" ,真正的同时执行!
重点: "串行执行" "并发执行" -----> 定理/原理性东西!
iOS中开启线程的方式:
pthread : 纯 C 的框架!
NSThread : OC 的框架! NSThread 内部封装的时 pthread! ---> 线程的概念!
GCD : 纯 C 的框架,使用最多的!
NSOpretion : 内部封装了 GCD ,是一种高级的并发编程方式!
线程状态:
{
// [alloc init] 线程对象!
'新建'
线程死亡或者销毁之后,就不能再次开启! 强行开启已经死亡的线程,会造成程序奔溃!
CPU 区分哪些线程需要执行,哪些不需要执行?
'阻塞/挂起' 就是将当前线程由可调度线程池"移出"!
可调度线程池: CPU 只执行可调度线程池中的线程!
{
CPU 调度当前线程的时候 线程中任务执行完毕
"就绪" ------------------------> "运行" ----------------------> '销毁/死亡'
CPU 调度/执行 其他线程 CPU 再次执行/调度当前线程
"运行" ------------------------> "就绪" --------------------------> "运行"
sleep 方法/互斥锁 sleep 时间到了/解锁 CPU调度当前线程
"运行" ------------------------> '阻塞/挂起' ----------------------> "就绪" -----------------> "运行"
exit 方法
"运行" -----------------------> '销毁/死亡'
}
}
优先级反转:
在可调度线程池中有三条线程! 三条线程的优先级分别为高,中,低
高优先级线程 和 低优先级线程 之间存在"互斥锁"! 高 和 低 同一时间内只能有一条线程位于可调度线程池中!
可调度线程池:
{
'高' "中" 低
}
互斥锁
线程按顺序执行--------> "线程同步技术"!
互斥锁: 为 set 和 get 方法都加锁! 一定能够保证安全!为了保证'内存中的有些区域'只允许一个对象访问!
私密区域: 只有一个对象能够访问
公共区域: 所有对象都能够访问
有限的公共区域: 只能够允许固定数量的对象访问 :信号量,决定了同时最多有多少个对象访问! 互斥锁就是信号量为1的特殊情况!
原子锁: 只为 set 方法加锁,不会为 get 方法加锁! 原子锁不能解决卖票的问题!会然线程以死循环的方式来等待解锁!轻量级!
nonatomic:非原子属性,不是线程安全的!效率比较高! 移动端选择非原子属性,有限满足性能需求!
atomic:原子属性,是线程安全的! 耗费性能!
原子锁的添加:
开发中遵循的原则: 复杂的业务逻辑/需要加锁的代码,尽量交给服务器去完成!
UI操作为什么放在主线程执行? '网络回调的代码要注意线程'! 注意: reloadData 是一个 UI 操作,一定要放在主线程!
{
1. 主线程 --- UI线程,所有的 UI 操作都放在主线程执行! 优先保证与用户交互!
2. UIKit 框架 都不是线程安全的! 为了保证线程安全,所有的 UI 操作都放在主线程!
}
客户端来说,开启线程有什么要求:
{
1. 所有的耗时操作(所有的网络请求必须放在子线程!/大数据的计算/复杂的计算/文件解压缩操作)必须放在子线程执行!
2. 所有的 UI 操作都放在主线程!
3. 不同线程之间数据的交换(线程间通信!)需要保证安全!包保证顺序!
}
iOS 开发
{
1. 线程一般最多开启 6 (3 ~ 5)条.
2. 如果是面向线程对象开打,需要手动管理线程的生命周期! (GCD 不需要!)
}
GCD(大中央调度器/NB的中枢调度器/任务派发器) :为了取代 NSThread . 可以充分发挥设备多核的性能!
NSThread: iOS 2.0 就推出了 (4S 之前都是单核 CPU)
GCD : 纯 C 框架,但是不需要手动管理内存! 效率非常高!
面向"任务"开发! --- 程序员只要将代码写好,并且将代码放在不同的"队列"中,选择不同的"执行方式",就可以决定是否开启线程!