前言
NSThread 基于OC的API,使用其简单,面向对象操作。但线程周期由程序员管理。
优点:轻量级
缺点:需要自己管理线程的生命周期,线程同步。线程同步对数据的加锁会有一定的系统开销
苹果推荐是用GCD 和 NSOperation
注意:
[NSThread currentThread]跟踪任务所在线程,适用于NSThread、NSOperation、GCD
使用NSThread的线程,不会自动添加autoreleasepool
线程中的自动释放池:
@autoreleasepool{}自动释放池。主线程中是有自动释放池,使用NSThread 和 NSObject 不会有。如果在后台线程中创建了autoreleasepool的对象,需要使用自动释放池,否则会出现内存泄漏。当自动释放池销毁时,对池中的所有对象发送release消息,清空自动释放池。当所有的autorelease对象,在出了作用域后,会自动添加到最近一次创建的自动释放池中。
NSThread 常用属性
1 | @property (nullable, copy) NSString *name //线程名字 |
NSThread类方法 作用于当前线程
1 | + (void)detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(nullable id)argument; //开辟一个新的线程 |
NSThread实例方法
1 | - (instancetype)init |
NSThread 详解
线程的生命周期
- 创建线程的方法
1 | - (instancetype)initWithTarget:(id)target selector:(SEL)selector object:(id)argument //此方法创建的线程需要手动启动 |
- 配置线程
1 | //通过name属性设置线程名字 |
- 启动线程
1 | - (void)start |
- 阻塞线程
1 | + (void)sleepUntilDate:(NSDate *)date |
- 取消线程
1 | - (void)cancel //当前正在执行的线程不会立刻停止 |
- 强制退出线程
1 | + (void)exit |
NSThread的其他操作
- 与主线程相关
1 | + (NSThread *)mainThread //获取主线程 |
- 与当前线程相关
1 | + (NSThread *)currentThread //获取当前线程 |
- 判断线程的状态
1 | * 通过executing属性判断线程是否正在执行 |
- 线程同步
- 原因:多个线程访问同一资源,很可能会引起数据错乱和数据安全问题
- 解决方案:使用互斥锁来解决互斥资源访问问题,iOS中通常使用@synchronized(锁){}对临界资源进行锁定,通常使用self作为锁
- 注意:由于线程同步会消耗大量的资源,应尽量避免多个线程访问同一资源,且通常将线程同步的逻辑交由服务器端实现
线程之间的通信
- 从子线程回到主线程
1 | - (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait modes:(NSArray *)array |
- 从一个线程到另一个线程(包括主线程)
1 | - (void)performSelector:(SEL)aSelector onThread:(NSThread )thr withObject:(id)arg waitUntilDone:(BOOL)wait modes:(NSArray )array |
也可以通过NSPort对象实现通信
反思
资源共享
- 1块资源可能会被多个线程共享,也就是多个线程可能会访问同一块资源
- 当多个线程访问同一块资源时,很容易引发数据错乱和数据安全问题
解决办法互斥锁
- 互斥锁使用格式
1.@synchronized(锁对象) { // 需要锁定的代码 }
2.只用一把锁,多锁是无效的
- 互斥锁的优缺点
优点:能有效防止因多线程抢夺资源造成的数据安全问题
缺点:需要消耗大量的CPU资源
- 互斥锁的使用前提:多条线程抢夺同一块资源