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];//延時當前線程

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM