一. NSThread开启新的线程
1. 创建并启动线程
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(loadData) object:nil];
[thread start];
- (void)loadData{
NSLog(@"%@", [NSThread currentThread]);
}
<NSThread: 0x600000eecc80>{number = 3, name = (null)}
2. 创建并启动线程
[NSThread detachNewThreadSelector:@selector(loadData) toTarget:self withObject:nil];
- (void)loadData{
NSLog(@"%@", [NSThread currentThread]);
}
<NSThread: 0x6000028049c0>{number = 3, name = (null)}
3. 隐式创建线程并启动
[self performSelectorInBackground:@selector(loadData) withObject:nil];
- (void)loadData{
NSLog(@"%@", [NSThread currentThread]);
}
<NSThread: 0x600001848cc0>{number = 3, name = (null)}
二. NSThread多线程常用相关方法
1. 线程属性相关
// 获得主线程
+ (NSThread *)mainThread;
// 判断是否为主线程(对象方法)
- (BOOL)isMainThread;
// 判断是否为主线程(类方法)
+ (BOOL)isMainThread;
// 获得当前线程
NSThread *thread = [NSThread currentThread];
// 线程的名字——setter方法
- (void)setName:(NSString *)n;
// 线程的名字——getter方法
- (NSString *)name;
2. 线程状态控制相关
// 线程进入就绪状态 -> 运行状态。当线程任务执行完毕,自动进入死亡状态
// 启动线程方法
- (void)start;
// 阻塞(暂停)线程方法
// 线程进入阻塞状态
+ (void)sleepUntilDate:(NSDate *)date;
+ (void)sleepForTimeInterval:(NSTimeInterval)ti;
// 强制停止线程
// 线程进入死亡状态
+ (void)exit;
3. 线程执行操作相关
// 在主线程上执行操作
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait;
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait modes:(NSArray<NSString *> *)array;
// equivalent to the first method with kCFRunLoopCommonModes
// 在指定线程上执行操作
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait modes:(NSArray *)array NS_AVAILABLE(10_5, 2_0);
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait NS_AVAILABLE(10_5, 2_0);
// 在当前线程上执行操作,调用 NSObject 的 performSelector:相关方法
- (id)performSelector:(SEL)aSelector;
- (id)performSelector:(SEL)aSelector withObject:(id)object;
- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;
三. NSThread线程之间的通信
先开一个新的子线程执行耗时操作,然后回到主线程中刷新UI。
[NSThread detachNewThreadSelector:@selector(loadData) toTarget:self withObject:nil];
- (void)loadData{
NSLog(@"1.%@", [NSThread currentThread]);
[NSThread sleepForTimeInterval:2.0];
[self performSelectorOnMainThread:@selector(reloadUI) withObject:nil waitUntilDone:YES];
}
- (void)reloadUI{
NSLog(@"2.%@", [NSThread currentThread]);
}
1.<NSThread: 0x600001a57a80>{number = 3, name = (null)}
2.<NSThread: 0x600001a062c0>{number = 1, name = main}
四. 线程安全
需求:有时候,我们会在多个地方同时对同一个接口进行调用,那如果每次调用过程会对下一次调用的结果有影响(有修改或者更变等操作),那么我们就必须保证该接口同一时间只能被一个地方调用,这就是线程安全
。
- (void)viewDidLoad {
[super viewDidLoad];
for (int i = 0; i < 10; i ++) {
[NSThread detachNewThreadSelector:@selector(loadData) toTarget:self withObject:nil];
}
}
- (void)loadData{
@synchronized (self) {
// 模拟耗时操作
[NSThread sleepForTimeInterval:1.0];
NSLog(@"---");
}
}
注:@synchronized
的作用是创建一个互斥锁
,这个指令可以将{ }
内的代码限制在一个线程执行,如果某个线程没有执行完,其他的线程如果需要执行就得等着,起到线程的保护作用。
五. 线程状态总结
- 当线程创建之后被启动,进入
就绪状态
。 - 当线程被
CPU
调度,进入运行状态
。 - 当
CPU
去调度其他线程,回到就绪状态
。 - 当
CPU
在运行当前线程对象的时候调用了sleep
方法或者等待同步锁
,进入阻塞状态
。等到sleep
到时或者得到同步锁
,则回到就绪状态
。 - 当
CPU
在运行当前线程对象的时候线程任务执行完毕或者异常强制退出,则当前线程对象进入死亡状态
。