这篇博客是接着总篇iOS GCD NSOperation NSThread等多线程各种举例详解写的一个支篇。总篇也包含了此文的链接。本文讲解的知识点有NSThread的开始、取消、在当前线程执行任务、线程通信、线程同步、延时函数等。附上:demo下载地址。
一、NSThread介绍
优点:NSThread 比其他两个轻量级。
缺点:需要自己管理线程的生命周期,线程同步。线程同步对数据的加锁会有一定的系统开销。
二、开始和取消
举个例子,注释写的很详细,不多说啦。
//开始
- (IBAction)start:(id)sender {
//实例方法开始
_myThread = [[NSThread alloc]initWithTarget:self selector:@selector(startCount) object:nil];
[_myThread start];
//静态方法开始
// [NSThread detachNewThreadSelector:@selector(startCount) toTarget:self withObject:nil];
//隐式开始
// [self performSelectorInBackground:@selector(startCount) withObject:nil];
}
//计时
-(void)startCount {
for (NSInteger i = 0; i< 1000; i++) {
//根据线程是否取消的标志位退出该任务
if (_myThread.cancelled) {
return;
}
[NSThread sleepForTimeInterval:1.0f];
NSLog(@"%ld",i);
}
}
//取消线程
- (IBAction)cancel:(id)sender {
//并没有真正取消该线程,只是给该线程设置了一个标志位
[_myThread cancel];
}
注意:[_myThread cancel];并没有取消该线程,只是给该线程设置了一个标志位,需要到具体任务里根据线程的.cancelled属性判断来取消。
三、线程通信
开一个子线程执行某任务,完成后回到主线程更新UI,实现线程通信,举个例子。
//线程通信
- (IBAction)communication:(id)sender {
//开一个子线程执行某任务,完成后回到主线程更新UI,实现线程通信
[NSThread detachNewThreadSelector:@selector(communicationTask) toTarget:self withObject:nil];
}
//线程通信任务
- (void)communicationTask {
NSLog(@"当前线程%@",[NSThread currentThread]);
//模拟一个3秒的任务,完成后到主线程更新UI
[NSThread sleepForTimeInterval:3];
[self performSelectorOnMainThread:@selector(updateUI:) withObject:[UIColor redColor] waitUntilDone:YES];
}
//更新UI
- (void)updateUI:(UIColor *)color {
self.view.backgroundColor = color;
NSLog(@"我变红了%@",[NSThread currentThread]);
}
打印结果:
分析结论:从communicationTask所在线程回到主线程更新了UI,实现了线程间通信。
四、线程同步
NSThread是要自己管理线程同步的,让同一个时间只有一个线程操作该数据,那么我们就要用到加锁。
@interface NSThreadViewController ()
{
NSInteger tickets;//剩余票数
NSInteger sellNum;//卖出票数
NSThread* thread1;//买票线程1
NSThread* thread2;//买票线程2
NSLock *theLock;//锁
}
@property (nonatomic, strong) NSThread* myThread;
@end
//(线程同步)2人抢票
- (IBAction)twoPeopleBuy:(id)sender {
tickets = 9;
sellNum = 0;
theLock = [[NSLock alloc] init];
thread1 = [[NSThread alloc] initWithTarget:self selector:@selector(buy) object:nil];
[thread1 setName:@"Thread-1"];
[thread1 start];
thread2 = [[NSThread alloc] initWithTarget:self selector:@selector(buy) object:nil];
[thread2 setName:@"Thread-2"];
[thread2 start];
}
//买票
-(void)buy{
while (TRUE) {
//上锁
[theLock lock];
if(tickets >= 0){
[NSThread sleepForTimeInterval:0.09];
sellNum = 9 - tickets;
NSLog(@"当前票数是:%ld,售出:%ld,线程名:%@",tickets,sellNum,[[NSThread currentThread] name]);
tickets--;
}else{
break;
}
[theLock unlock];
}
}
打印结果:
分析结论:加锁来实现线程同步后,票是一张一张卖出去的。当把锁去掉就会出现如下局面:
两个线程同时操作一个数据,最后出现了负数。
五、NSThread延时
此方式在主线程和子线程中均可执行。是一种阻塞的执行方式,建方放到子线程中,以免卡住界面,没有找到取消执行的方法。
[NSThread sleepForTimeInterval:3];//延时当前线程