多线程工作原理
->是CPU快速的在多个线程之间的切换
->由于执行的速度快,就早造成了同时执行的一种假象
->如果线程数非常多,CPU会在会在多个线程之间切换,消耗大量的CPU资源
->每一个线程被调度的次数会降低,线程的执行效率降低
多线程的优点和缺点
优点
->能适当提高程序的执行效率
->能适当提高资源的利用率(CPU 内存)
->线程上的任务执行完成后,线程UI自动销毁
缺点
->开启线程需要占用一定的内存空间(默认情况下,每一个线程都占512kb)
->如果开启大量的线程,会占用大量的内存空间,降低程序的性能
->线程越多,CPU在调用线程上的开销就越大(空间开销,时间开销)
->程序设计更加复杂,比如多线程的数据共享.线程间的通信
建议:多线程不是越多越好,只在适当的时候开启多线程(耗时操作的时候)
主线程
->一个程序运行后,默认会开启一个线程,成为"主线程”或者"UI线程"
->主线程一般用来刷新UI界面,处理UI事件(比如:点击 滚动 拖拽等事件)
->子线程在执行耗时操作
注意:
->别将耗时操作放到主线程中
IOS中多线程的技术方案
1.pthread
—>导入头文件 #include <pthread.h>
第一个参数:子线程的编号/代号/ID,传入地址
第二个参数:子线程的属性,传入地址 .NULL,空指针 nil,空对象
第三个参数:指定子线程执行的对象
void * (*) (void *)
返回值 函数名 函数的参数
void * : 是C语言中,可以指向任何地址的指针.类似于OC中的id(万能对象指针,可以指向任何对象的地址)
函数的地址就是函数名
第四个参数:传入到指定子线程执行的函数的参数
该方法的返回值是: int 创建子线程成功返回0,失败返回非0;
<NSThread: 0x7fa9a270a870>{number = 2, name = (null)}
number != 1.代表当前线程是子线程
<NSThread: 0x7fcf72202bf0>{number = 1, name = main}
number = 1.代表当前线程是主线程
建议 : 千万不要纠结number到底等于几.
__bridge : 桥接
MRC : 谁申请,谁释放
ARC : 编译器在编译代码的时候,会根据的代码结构自动的添加release,retain,autorelease语句
ARC环境下,编译器不会处理C语言申请的内存空间.我们做C语言和OC语言混合开发的时候,需要使用桥接
目的 : 告诉编译器如何处理内存.即,什么都不做.
提问 : MRC环境下使用桥接吗?
不需要.因为内存手动管理的
2.NSThread
创建线程的三种方式
方式1:对象方法创建
启动线程对象:[thread start];
方式2:类方法创建
detach : 分离
这种创建线程的方式无法获取到对象,自动启动线程.
方式3:隐式创建
这种创建线程的方法继承自:
@interface NSObject (NSThreadPerformAdditions)
任何继承自 NSObject 的对象都可以很方便的创建线程对象
共享资源
资源:一个对象 一个变量 一个文件
共享资源:全局的变量 对象 文件 ,可以被其他对象访问的资源
->一块资源可能会被多个线程共享,也就是多个线程可能会操作同一 块资源
注:当多个线程操作同一块资源师,很容易引发数据错乱和数据安全问题,为了解决这一问题,引入”锁”的概念
1.互斥锁(线程同步)
互斥锁能有效防止因多线程抢夺资源造成的数据安全问题
线程同步:多条线程按顺序执行任务
self : 锁对象.任何继承自NSObject的对象都是锁对象.因为内部都有一把锁,默认是开启的
锁对象必须是全局的.self是最方便的全局的锁对象
特点 : 能够保证被锁定的代码,在同一时间,只有一个线程可以操作
使用原则 : 必须锁定共享资源的读写部分,而且锁定的范围必须小
补充 : 加锁保证了安全,但是牺牲了性能/效率
局部的锁对象,锁不住的.
互斥锁原理
原子属性
原子属性 : 单写多度,单个线程写入,多个线程可以读取
原理 : setter方法内部加了一把自旋锁,自旋锁看不见.
IOS开发建议:所有属性都声明为nonatomic
nonatomic和atomic对比
->atomic:线程安全,需要消耗大量的资源
->nonatomic:非线程安全,适合内存小得移动设备
互斥锁和自旋锁
![]()
![]()
weak和strong
OC对象用strong修饰
UI控件用weak修饰,当这个UI控件作为跟视图的时候,用strong修饰
![]()
IOS中的内存管理
![]()
自动释放池
![]()
自动释放池关键问题
![]()
什么时候使用自动释放池?
如果在循环中创建了大量的临时变量的时候需要在循环一开始就手动创建一个自动释放池
注:如果你生成了一个子线程的时候,要在线程开始执行的时候,尽量创建一个自动释放池,否则会内存泄露.因为子线程无法访问主线程的自动释放池
消息循环的作用
1. 保证应用程序不退出
2. 循环的检测事件,并且执行事件对应的方法