ios 多线程之NSThread篇举例详解

  这篇博客是接着总篇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];//延时当前线程

 

posted @ 2015-11-20 13:57  张林峰  阅读(3325)  评论(0编辑  收藏  举报